airoha: Introduce EN7581 SoC support

Introduce EN7581 SoC support with currently rfb board supported.

This is a new 64bit SoC from Airoha that is currently almost fully
supported upstream with only the DTS missing. Setting source-only
waiting for the full upstream support to be completed.

Link: https://github.com/openwrt/openwrt/pull/16730
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi 2024-10-17 15:54:52 +02:00
parent c5f38c1fd0
commit 9131cb44ff
No known key found for this signature in database
GPG Key ID: AC001D09ADBFEAD7
74 changed files with 23628 additions and 4 deletions

View File

@ -3,8 +3,8 @@ include $(TOPDIR)/rules.mk
ARCH:=arm
BOARD:=airoha
BOARDNAME:=Airoha ARM
SUBTARGETS:=en7523
FEATURES:=dt squashfs nand ramdisk gpio source-only
SUBTARGETS:=en7523 en7581
FEATURES:=dt squashfs nand ramdisk gpio
KERNEL_PATCHVER:=6.6

View File

@ -0,0 +1,210 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/dts-v1/;
/* Bootloader installs ATF here */
/memreserve/ 0x80000000 0x200000;
#include <dt-bindings/leds/common.h>
#include <dt-bindings/gpio/gpio.h>
#include "en7581.dtsi"
/ {
model = "Airoha EN7581 Evaluation Board";
compatible = "airoha,en7581-evb", "airoha,en7581";
aliases {
serial0 = &uart1;
};
chosen {
bootargs = "console=ttyS0,115200 earlycon";
stdout-path = "serial0:115200n8";
linux,usable-memory-range = <0x0 0x80200000 0x0 0x1fe00000>;
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x2 0x00000000>;
};
};
&en7581_pinctrl {
gpio-ranges = <&en7581_pinctrl 0 13 47>;
mdio_pins: mdio-pins {
mux {
function = "mdio";
groups = "mdio";
};
conf {
pins = "gpio2";
output-high;
};
};
pcie0_rst_pins: pcie0-rst-pins {
conf {
pins = "pcie_reset0";
drive-open-drain = <1>;
};
};
pcie1_rst_pins: pcie1-rst-pins {
conf {
pins = "pcie_reset1";
drive-open-drain = <1>;
};
};
gswp1_led0_pins: gswp1-led0-pins {
mux {
function = "phy1_led0";
pins = "gpio33";
};
};
gswp2_led0_pins: gswp2-led0-pins {
mux {
function = "phy2_led0";
pins = "gpio34";
};
};
gswp3_led0_pins: gswp3-led0-pins {
mux {
function = "phy3_led0";
pins = "gpio35";
};
};
gswp4_led0_pins: gswp4-led0-pins {
mux {
function = "phy4_led0";
pins = "gpio42";
};
};
pwm_gpio18_idx10_pins: pwm-gpio18-idx10-pins {
function = "pwm";
pins = "gpio18";
output-enable;
};
mmc_pins: mmc-pins {
mux {
function = "emmc";
groups = "emmc";
};
};
};
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc_pins>;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
card@0 {
compatible = "mmc-card";
reg = <0>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
bootloader@0 {
label = "bootloader";
reg = <0x00000000 0x00080000>;
};
tclinux@80000 {
label = "tclinux";
reg = <0x00080000 0x02800000>;
};
tclinux_slave@2880000 {
label = "tclinux_slave";
reg = <0x02880000 0x02800000>;
};
rootfs_data@5080000 {
label = "rootfs_data";
reg = <0x5080000 0x00800000>;
};
};
};
};
&i2c0 {
status = "okay";
};
&pcie0 {
pinctrl-names = "default";
pinctrl-0 = <&pcie0_rst_pins>;
status = "okay";
};
&pcie1 {
pinctrl-names = "default";
pinctrl-0 = <&pcie1_rst_pins>;
status = "okay";
};
&eth {
status = "okay";
};
&gdm1 {
status = "okay";
};
&switch {
pinctrl-names = "default";
pinctrl-0 = <&mdio_pins>;
status = "okay";
};
&gsw_phy1 {
pinctrl-names = "led";
pinctrl-0 = <&gswp1_led0_pins>;
status = "okay";
};
&gsw_phy1_led0 {
status = "okay";
};
&gsw_phy2 {
pinctrl-names = "led";
pinctrl-0 = <&gswp2_led0_pins>;
status = "okay";
};
&gsw_phy2_led0 {
status = "okay";
};
&gsw_phy3 {
pinctrl-names = "led";
pinctrl-0 = <&gswp3_led0_pins>;
status = "okay";
};
&gsw_phy3_led0 {
status = "okay";
};
&gsw_phy4 {
pinctrl-names = "led";
pinctrl-0 = <&gswp4_led0_pins>;
status = "okay";
};
&gsw_phy4_led0 {
status = "okay";
};

View File

@ -0,0 +1,254 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/dts-v1/;
/* Bootloader installs ATF here */
/memreserve/ 0x80000000 0x200000;
#include <dt-bindings/leds/common.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "en7581.dtsi"
/ {
model = "Airoha EN7581 Evaluation Board";
compatible = "airoha,en7581-evb", "airoha,en7581";
aliases {
serial0 = &uart1;
};
chosen {
bootargs = "console=ttyS0,115200 earlycon";
stdout-path = "serial0:115200n8";
linux,usable-memory-range = <0x0 0x80200000 0x0 0x1fe00000>;
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x2 0x00000000>;
};
gpio-keys-polled {
compatible = "gpio-keys-polled";
poll-interval = <100>;
btn0 {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&en7581_pinctrl 0 GPIO_ACTIVE_LOW>;
};
};
pwmleds {
compatible = "pwm-leds";
pinctrl-names = "default";
pinctrl-0 = <&pwm_gpio18_idx10_pins>;
lan4_green {
label = "pon:green";
pwms = <&en7581_pwm 10 4000000 0>;
max-brightness = <255>;
active-low;
};
};
leds {
compatible = "gpio-leds";
pwr_led: led-0 {
label = "pwr";
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_POWER;
gpios = <&en7581_pinctrl 17 GPIO_ACTIVE_LOW>;
default-state = "on";
};
los_led: led-2 {
label = "los";
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 19 GPIO_ACTIVE_LOW>;
default-state = "on";
};
internet_led: led-3 {
label = "internet";
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 20 GPIO_ACTIVE_LOW>;
default-state = "on";
};
};
};
&en7581_pinctrl {
gpio-ranges = <&en7581_pinctrl 0 13 47>;
mdio_pins: mdio-pins {
mux {
function = "mdio";
groups = "mdio";
};
conf {
pins = "gpio2";
output-high;
};
};
pcie0_rst_pins: pcie0-rst-pins {
conf {
pins = "pcie_reset0";
drive-open-drain = <1>;
};
};
pcie1_rst_pins: pcie1-rst-pins {
conf {
pins = "pcie_reset1";
drive-open-drain = <1>;
};
};
gswp1_led0_pins: gswp1-led0-pins {
mux {
function = "phy1_led0";
pins = "gpio33";
};
};
gswp2_led0_pins: gswp2-led0-pins {
mux {
function = "phy2_led0";
pins = "gpio34";
};
};
gswp3_led0_pins: gswp3-led0-pins {
mux {
function = "phy3_led0";
pins = "gpio35";
};
};
gswp4_led0_pins: gswp4-led0-pins {
mux {
function = "phy4_led0";
pins = "gpio42";
};
};
pwm_gpio18_idx10_pins: pwm-gpio18-idx10-pins {
function = "pwm";
pins = "gpio18";
output-enable;
};
};
&snfi {
status = "okay";
};
&spi_nand {
partitions {
compatible = "airoha,fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
bootloader@0 {
label = "bootloader";
reg = <0x00000000 0x00080000>;
};
tclinux@80000 {
label = "tclinux";
compatible = "denx,fit";
reg = <0x00080000 0x02800000>;
};
tclinux_slave@2880000 {
label = "tclinux_slave";
reg = <0x02880000 0x02800000>;
};
rootfs_data@5080000 {
label = "rootfs_data";
reg = <0x5080000 0x00800000>;
};
art@ffffffff {
compatible = "airoha,dynamic-art";
label = "art";
reg = <0xffffffff 0x00300000>;
};
};
};
&i2c0 {
status = "okay";
};
&pcie0 {
pinctrl-names = "default";
pinctrl-0 = <&pcie0_rst_pins>;
status = "okay";
};
&pcie1 {
pinctrl-names = "default";
pinctrl-0 = <&pcie1_rst_pins>;
status = "okay";
};
&eth {
status = "okay";
};
&gdm1 {
status = "okay";
};
&switch {
pinctrl-names = "default";
pinctrl-0 = <&mdio_pins>;
status = "okay";
};
&gsw_phy1 {
pinctrl-names = "led";
pinctrl-0 = <&gswp1_led0_pins>;
status = "okay";
};
&gsw_phy1_led0 {
status = "okay";
};
&gsw_phy2 {
pinctrl-names = "led";
pinctrl-0 = <&gswp2_led0_pins>;
status = "okay";
};
&gsw_phy2_led0 {
status = "okay";
};
&gsw_phy3 {
pinctrl-names = "led";
pinctrl-0 = <&gswp3_led0_pins>;
status = "okay";
};
&gsw_phy3_led0 {
status = "okay";
};
&gsw_phy4 {
pinctrl-names = "led";
pinctrl-0 = <&gswp4_led0_pins>;
status = "okay";
};
&gsw_phy4_led0 {
status = "okay";
};

View File

@ -0,0 +1,756 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/en7523-clk.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
npu-binary@84000000 {
no-map;
reg = <0x0 0x84000000 0x0 0xa00000>;
};
npu-flag@84b0000 {
no-map;
reg = <0x0 0x84b00000 0x0 0x100000>;
};
npu-pkt@85000000 {
no-map;
reg = <0x0 0x85000000 0x0 0x1a00000>;
};
npu-phyaddr@86b00000 {
no-map;
reg = <0x0 0x86b00000 0x0 0x100000>;
};
npu-rxdesc@86d00000 {
no-map;
reg = <0x0 0x86d00000 0x0 0x100000>;
};
};
psci {
compatible = "arm,psci-1.0";
method = "smc";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu0>;
};
core1 {
cpu = <&cpu1>;
};
core2 {
cpu = <&cpu2>;
};
core3 {
cpu = <&cpu3>;
};
};
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x0>;
operating-points-v2 = <&cpu_opp_table>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&l2>;
#cooling-cells = <2>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x1>;
operating-points-v2 = <&cpu_opp_table>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&l2>;
#cooling-cells = <2>;
};
cpu2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x2>;
operating-points-v2 = <&cpu_opp_table>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&l2>;
#cooling-cells = <2>;
};
cpu3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x3>;
operating-points-v2 = <&cpu_opp_table>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&l2>;
#cooling-cells = <2>;
};
l2: l2-cache {
compatible = "cache";
cache-size = <0x80000>;
cache-line-size = <64>;
cache-level = <2>;
cache-unified;
};
};
cpu_opp_table: opp-table {
compatible = "operating-points-v2";
opp-shared;
opp-500000000 {
opp-hz = /bits/ 64 <500000000>;
};
opp-550000000 {
opp-hz = /bits/ 64 <550000000>;
};
opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
};
opp-650000000 {
opp-hz = /bits/ 64 <650000000>;
};
opp-7000000000 {
opp-hz = /bits/ 64 <700000000>;
};
opp-7500000000 {
opp-hz = /bits/ 64 <750000000>;
};
opp-8000000000 {
opp-hz = /bits/ 64 <800000000>;
};
opp-8500000000 {
opp-hz = /bits/ 64 <850000000>;
};
opp-9000000000 {
opp-hz = /bits/ 64 <900000000>;
};
opp-9500000000 {
opp-hz = /bits/ 64 <950000000>;
};
opp-10000000000 {
opp-hz = /bits/ 64 <1000000000>;
};
opp-10500000000 {
opp-hz = /bits/ 64 <1050000000>;
};
opp-11000000000 {
opp-hz = /bits/ 64 <1100000000>;
};
opp-11500000000 {
opp-hz = /bits/ 64 <1150000000>;
};
opp-12000000000 {
opp-hz = /bits/ 64 <1200000000>;
};
};
timer {
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
};
thermal-zones {
cpu_thermal: cpu-thermal {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&thermal 0>;
trips {
cpu_hot: cpu-hot {
temperature = <95000>;
hysteresis = <1000>;
type = "hot";
};
cpu-critical {
temperature = <110000>;
hysteresis = <1000>;
type = "critical";
};
};
cooling-maps {
map0 {
trip = <&cpu_hot>;
cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
};
};
};
soc {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
gic: interrupt-controller@9000000 {
compatible = "arm,gic-v3";
interrupt-controller;
#interrupt-cells = <3>;
#address-cells = <1>;
#size-cells = <1>;
reg = <0x0 0x09000000 0x0 0x20000>,
<0x0 0x09080000 0x0 0x80000>,
<0x0 0x09400000 0x0 0x2000>,
<0x0 0x09500000 0x0 0x2000>,
<0x0 0x09600000 0x0 0x20000>;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
};
uart1: serial@1fbf0000 {
compatible = "ns16550";
reg = <0x0 0x1fbf0000 0x0 0x30>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <1843200>;
};
watchdog@1fbf0100 {
compatible = "airoha,en7581-wdt";
reg = <0x0 0x1fbf0100 0x0 0x38>;
clocks = <&scuclk EN7523_CLK_BUS>;
clock-names = "bus";
};
uart2: serial@1fbf0300 {
compatible = "airoha,en7523-uart";
reg = <0x0 0x1fbf0300 0x0 0x30>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <7372800>;
status = "disabled";
};
hsuart3: serial@1fbe1000 {
compatible = "airoha,en7523-uart";
reg = <0x0 0x1fbe1000 0x0 0x40>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <7372800>;
status = "disabled";
};
uart4: serial@1fbf0600 {
compatible = "airoha,en7523-uart";
reg = <0x0 0x1fbf0600 0x0 0x30>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <7372800>;
status = "disabled";
};
uart5: serial@1fbf0700 {
compatible = "airoha,en7523-uart";
reg = <0x0 0x1fbf0700 0x0 0x30>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <7372800>;
status = "disabled";
};
chip_scu: syscon@1fa20000 {
compatible = "airoha,en7581-chip-scu", "syscon";
reg = <0x0 0x1fa20000 0x0 0x388>;
};
syscon@1fbe3400 {
compatible = "airoha,en7581-pbus-csr", "syscon";
reg = <0x0 0x1fbe3400 0x0 0xff>;
};
scuclk: clock-controller@1fa20000 {
compatible = "airoha,en7581-scu";
reg = <0x0 0x1fb00000 0x0 0x970>;
#clock-cells = <1>;
#reset-cells = <1>;
};
rng@1faa1000 {
compatible = "airoha,en7581-trng";
reg = <0x0 0x1faa1000 0x0 0xc04>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
};
crypto@1e004000 {
compatible = "inside-secure,safexcel-eip93ies";
reg = <0x0 0x1fb70000 0x0 0x1000>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
};
thermal: thermal-sensor@1efbd800 {
compatible = "airoha,en7581-thermal";
reg = <0x0 0x1efbd000 0x0 0xd5c>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
airoha,chip-scu = <&chip_scu>;
#thermal-sensor-cells = <0>;
};
system-controller@1fbf0200 {
compatible = "syscon", "simple-mfd";
reg = <0x0 0x1fbf0200 0x0 0xc0>;
en7581_pinctrl: pinctrl {
compatible = "airoha,en7581-pinctrl";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
en7581_pwm: pwm {
compatible = "airoha,en7581-pwm";
#pwm-cells = <3>;
};
};
i2cclock: i2cclock@0 {
#clock-cells = <0>;
compatible = "fixed-clock";
/* 20 MHz */
clock-frequency = <20000000>;
};
i2c0: i2c0@1fbf8000 {
compatible = "mediatek,mt7621-i2c";
reg = <0x0 0x1fbf8000 0x0 0x100>;
clocks = <&i2cclock>;
/* 100 kHz */
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
status = "disable";
};
i2c1: i2c1@1fbf8100 {
compatible = "mediatek,mt7621-i2c";
reg = <0x0 0x1fbf8100 0x0 0x100>;
clocks = <&i2cclock>;
/* 100 kHz */
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
status = "disable";
};
snfi: spi@1fa10000 {
compatible = "airoha,en7581-snand";
reg = <0x0 0x1fa10000 0x0 0x140>,
<0x0 0x1fa11000 0x0 0x160>;
clocks = <&scuclk EN7523_CLK_SPI>;
clock-names = "spi";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
spi_nand: nand@0 {
compatible = "spi-nand";
reg = <0>;
spi-max-frequency = <50000000>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <2>;
airoha,bmt;
};
};
mmc0: mmc@1fa0e000 {
compatible = "mediatek,mt7622-mmc";
reg = <0x0 0x1fa0e000 0x0 0x1000>,
<0x0 0x1fa0c000 0x0 0x60>;
interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
bus-width = <4>;
max-frequency = <52000000>;
disable-wp;
cap-mmc-highspeed;
non-removable;
status = "disabled";
};
pciephy: phy@1fa5a000 {
compatible = "airoha,en7581-pcie-phy";
reg = <0x0 0x1fa5a000 0x0 0xfff>,
<0x0 0x1fa5b000 0x0 0xfff>,
<0x0 0x1fa5c000 0x0 0xfff>,
<0x0 0x1fc10044 0x0 0x4>,
<0x0 0x1fc30044 0x0 0x4>,
<0x0 0x1fc15030 0x0 0x104>;
reg-names = "csr-2l", "pma0", "pma1",
"p0-xr-dtime", "p1-xr-dtime",
"rx-aeq";
#phy-cells = <0>;
};
pcie0: pcie@1fc00000 {
compatible = "airoha,en7581-pcie";
device_type = "pci";
linux,pci-domain = <0>;
#address-cells = <3>;
#size-cells = <2>;
reg = <0x0 0x1fc00000 0x0 0x1670>;
reg-names = "pcie-mac";
clocks = <&scuclk EN7523_CLK_PCIE>;
clock-names = "sys-ck";
phys = <&pciephy>;
phy-names = "pcie-phy";
ranges = <0x02000000 0 0x20000000 0x0 0x20000000 0 0x4000000>;
resets = <&scuclk EN7581_PCIE0_RST>,
<&scuclk EN7581_PCIE1_RST>,
<&scuclk EN7581_PCIE2_RST>;
reset-names = "phy-lane0", "phy-lane1", "phy-lane2";
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
bus-range = <0x00 0xff>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
<0 0 0 3 &pcie_intc0 2>,
<0 0 0 4 &pcie_intc0 3>;
status = "disabled";
pcie_intc0: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
pcie1: pcie@1fc20000 {
compatible = "airoha,en7581-pcie";
device_type = "pci";
linux,pci-domain = <1>;
#address-cells = <3>;
#size-cells = <2>;
reg = <0x0 0x1fc20000 0x0 0x1670>;
reg-names = "pcie-mac";
clocks = <&scuclk EN7523_CLK_PCIE>;
clock-names = "sys-ck";
phys = <&pciephy>;
phy-names = "pcie-phy";
ranges = <0x02000000 0 0x24000000 0x0 0x24000000 0 0x4000000>;
resets = <&scuclk EN7581_PCIE0_RST>,
<&scuclk EN7581_PCIE1_RST>,
<&scuclk EN7581_PCIE2_RST>;
reset-names = "phy-lane0", "phy-lane1", "phy-lane2";
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
bus-range = <0x00 0xff>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
<0 0 0 3 &pcie_intc1 2>,
<0 0 0 4 &pcie_intc1 3>;
status = "disabled";
pcie_intc1: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
eth: ethernet@1fb50000 {
compatible = "airoha,en7581-eth";
reg = <0 0x1fb50000 0 0x2600>,
<0 0x1fb54000 0 0x2000>,
<0 0x1fb56000 0 0x2000>;
reg-names = "fe", "qdma0", "qdma1";
resets = <&scuclk EN7581_FE_RST>,
<&scuclk EN7581_FE_PDMA_RST>,
<&scuclk EN7581_FE_QDMA_RST>,
<&scuclk EN7581_XSI_MAC_RST>,
<&scuclk EN7581_DUAL_HSI0_MAC_RST>,
<&scuclk EN7581_DUAL_HSI1_MAC_RST>,
<&scuclk EN7581_HSI_MAC_RST>,
<&scuclk EN7581_XFP_MAC_RST>;
reset-names = "fe", "pdma", "qdma", "xsi-mac",
"hsi0-mac", "hsi1-mac", "hsi-mac",
"xfp-mac";
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
gdm1: ethernet@1 {
compatible = "airoha,eth-mac";
reg = <1>;
phy-mode = "internal";
status = "disabled";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
switch: switch@1fb58000 {
compatible = "airoha,en7581-switch";
reg = <0 0x1fb58000 0 0x8000>;
resets = <&scuclk EN7581_GSW_RST>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
#address-cells = <1>;
#size-cells = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
gsw_port1: port@1 {
reg = <1>;
label = "lan1";
phy-mode = "internal";
phy-handle = <&gsw_phy1>;
};
gsw_port2: port@2 {
reg = <2>;
label = "lan2";
phy-mode = "internal";
phy-handle = <&gsw_phy2>;
};
gsw_port3: port@3 {
reg = <3>;
label = "lan3";
phy-mode = "internal";
phy-handle = <&gsw_phy3>;
};
gsw_port4: port@4 {
reg = <4>;
label = "lan4";
phy-mode = "internal";
phy-handle = <&gsw_phy4>;
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gdm1>;
phy-mode = "internal";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
gsw_phy1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <9>;
phy-mode = "internal";
leds {
#address-cells = <1>;
#size-cells = <0>;
gsw_phy1_led0: gsw-phy1-led0@0 {
reg = <0>;
function = "phy1_led0";
status = "disabled";
};
gsw_phy1_led1: gsw-phy1-led1@1 {
reg = <1>;
function = "phy1_led1";
status = "disabled";
};
};
};
gsw_phy2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <10>;
phy-mode = "internal";
leds {
#address-cells = <1>;
#size-cells = <0>;
gsw_phy2_led0: gsw-phy2-led0@0 {
reg = <0>;
function = "phy2_led0";
status = "disabled";
};
gsw_phy2_led1: gsw-phy2-led1@1 {
reg = <1>;
function = "phy1_led1";
status = "disabled";
};
};
};
gsw_phy3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <11>;
phy-mode = "internal";
leds {
#address-cells = <1>;
#size-cells = <0>;
gsw_phy3_led0: gsw-phy3-led0@0 {
reg = <0>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
gsw_phy3_led1: gsw-phy3-led1@1 {
reg = <1>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
};
};
gsw_phy4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <12>;
phy-mode = "internal";
leds {
#address-cells = <1>;
#size-cells = <0>;
gsw_phy4_led0: gsw-phy4-led0@0 {
reg = <0>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
gsw_phy4_led1: gsw-phy4-led1@1 {
reg = <1>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
};
};
};
};
};
};

View File

@ -0,0 +1,616 @@
CONFIG_64BIT=y
CONFIG_AIROHA_THERMAL=y
CONFIG_AIROHA_WATCHDOG=y
CONFIG_AMPERE_ERRATUM_AC03_CPU_38=y
CONFIG_ARCH_AIROHA=y
CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_FORCE_MAX_ORDER=10
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
CONFIG_ARCH_MMAP_RND_BITS=18
CONFIG_ARCH_MMAP_RND_BITS_MAX=24
CONFIG_ARCH_MMAP_RND_BITS_MIN=18
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
CONFIG_ARCH_PROC_KCORE_TEXT=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_STACKWALK=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_USES_PG_ARCH_X=y
CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_ARCH_WANTS_THP_SWAP=y
CONFIG_ARM64=y
CONFIG_ARM64_4K_PAGES=y
CONFIG_ARM64_AMU_EXTN=y
CONFIG_ARM64_BTI=y
CONFIG_ARM64_E0PD=y
CONFIG_ARM64_EPAN=y
CONFIG_ARM64_ERRATUM_1024718=y
CONFIG_ARM64_ERRATUM_1165522=y
CONFIG_ARM64_ERRATUM_1286807=y
CONFIG_ARM64_ERRATUM_1319367=y
CONFIG_ARM64_ERRATUM_1463225=y
CONFIG_ARM64_ERRATUM_1508412=y
CONFIG_ARM64_ERRATUM_1530923=y
CONFIG_ARM64_ERRATUM_1542419=y
CONFIG_ARM64_ERRATUM_2051678=y
CONFIG_ARM64_ERRATUM_2054223=y
CONFIG_ARM64_ERRATUM_2067961=y
CONFIG_ARM64_ERRATUM_2077057=y
CONFIG_ARM64_ERRATUM_2441007=y
CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_2457168=y
CONFIG_ARM64_ERRATUM_2658417=y
CONFIG_ARM64_ERRATUM_819472=y
CONFIG_ARM64_ERRATUM_824069=y
CONFIG_ARM64_ERRATUM_826319=y
CONFIG_ARM64_ERRATUM_827319=y
CONFIG_ARM64_ERRATUM_832075=y
CONFIG_ARM64_ERRATUM_843419=y
CONFIG_ARM64_ERRATUM_858921=y
CONFIG_ARM64_HW_AFDBM=y
CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y
CONFIG_ARM64_MTE=y
CONFIG_ARM64_PAGE_SHIFT=12
CONFIG_ARM64_PA_BITS=48
CONFIG_ARM64_PA_BITS_48=y
CONFIG_ARM64_PTR_AUTH=y
CONFIG_ARM64_PTR_AUTH_KERNEL=y
CONFIG_ARM64_RAS_EXTN=y
CONFIG_ARM64_SME=y
CONFIG_ARM64_SVE=y
# CONFIG_ARM64_SW_TTBR0_PAN is not set
CONFIG_ARM64_TAGGED_ADDR_ABI=y
CONFIG_ARM64_TLB_RANGE=y
CONFIG_ARM64_VA_BITS=39
CONFIG_ARM64_VA_BITS_39=y
CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
CONFIG_ARM64_WORKAROUND_TSB_FLUSH_FAILURE=y
CONFIG_ARM_AIROHA_SOC_CPUFREQ=y
CONFIG_ARM_AMBA=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
CONFIG_ARM_GIC=y
CONFIG_ARM_GIC_V2M=y
CONFIG_ARM_GIC_V3=y
CONFIG_ARM_GIC_V3_ITS=y
CONFIG_ARM_GIC_V3_ITS_PCI=y
CONFIG_ARM_PMU=y
CONFIG_ARM_PMUV3=y
CONFIG_ARM_PSCI_FW=y
CONFIG_ARM_SMCCC_SOC_ID=y
# CONFIG_ARM_SMMU is not set
# CONFIG_ARM_SMMU_V3 is not set
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
CONFIG_BINFMT_MISC=y
# CONFIG_BLK_CGROUP is not set
CONFIG_BLK_DEBUG_FS=y
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_PM=y
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
# CONFIG_BPF_JIT is not set
# CONFIG_BPF_SYSCALL is not set
# CONFIG_BRIDGE_VLAN_FILTERING is not set
CONFIG_BUFFER_HEAD=y
CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y
CONFIG_CAVIUM_ERRATUM_22375=y
CONFIG_CAVIUM_ERRATUM_23154=y
CONFIG_CAVIUM_ERRATUM_27456=y
CONFIG_CAVIUM_ERRATUM_30115=y
CONFIG_CAVIUM_TX2_ERRATUM_219=y
CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
CONFIG_CC_NO_ARRAY_BOUNDS=y
# CONFIG_CFS_BANDWIDTH is not set
CONFIG_CGROUPS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_FREEZER=y
# CONFIG_CGROUP_NET_CLASSID is not set
# CONFIG_CGROUP_NET_PRIO is not set
# CONFIG_CGROUP_PERF is not set
# CONFIG_CGROUP_PIDS is not set
# CONFIG_CGROUP_RDMA is not set
CONFIG_CGROUP_SCHED=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_EN7523=y
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y
CONFIG_COREDUMP=y
CONFIG_CPUSETS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_ISOLATION=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MITIGATIONS=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CRC16=y
CONFIG_CRC_CCITT=y
CONFIG_CROSS_MEMORY_ATTACH=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_DEV_EIP93=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_GENIV=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_DES=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=y
# CONFIG_CRYPTO_PCRYPT is not set
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA3=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
CONFIG_DEBUG_INFO_NONE=y
CONFIG_DEBUG_MISC=y
CONFIG_DEVMEM=y
CONFIG_DMADEVICES=y
CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
CONFIG_DMA_DIRECT_REMAP=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_OPS=y
CONFIG_DTC=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_FAT_DEFAULT_CODEPAGE=936
CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
CONFIG_FAT_FS=y
CONFIG_FIXED_PHY=y
CONFIG_FIX_EARLYCON_MEM=y
# CONFIG_FORTIFY_SOURCE is not set
CONFIG_FRAME_POINTER=y
CONFIG_FREEZER=y
CONFIG_FSL_ERRATUM_A008585=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
CONFIG_FUJITSU_ERRATUM_010001=y
CONFIG_FUNCTION_ALIGNMENT=4
CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FWNODE_MDIO=y
CONFIG_FW_CACHE=y
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_GCC10_NO_ARRAY_BOUNDS=y
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ARCH_TOPOLOGY=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_GENERIC_CSUM=y
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IOREMAP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GLOB=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_EN7523=y
CONFIG_GPIO_GENERIC=y
CONFIG_GRO_CELLS=y
# CONFIG_HARDENED_USERCOPY is not set
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HISILICON_ERRATUM_161010101=y
CONFIG_HISILICON_ERRATUM_161600802=y
CONFIG_HOTPLUG_CORE_SYNC=y
CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
CONFIG_HOTPLUG_CPU=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_AIROHA=y
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
# CONFIG_INET_ESP_OFFLOAD is not set
CONFIG_INET_IPCOMP=y
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_TUNNEL=y
CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_KEYBOARD=y
# CONFIG_INPUT_MISC is not set
CONFIG_INTERVAL_TREE=y
CONFIG_INTERVAL_TREE_SPAN_ITER=y
CONFIG_IOMMUFD=y
CONFIG_IOMMU_API=y
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_IOMMU_DMA=y
CONFIG_IOMMU_IOVA=y
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
# CONFIG_IOMMU_IO_PGTABLE_DART is not set
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
CONFIG_IOMMU_SUPPORT=y
CONFIG_IO_URING=y
CONFIG_IPC_NS=y
CONFIG_IPV6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_IPV6_SUBTREES is not set
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_COMMON=y
# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_RARP is not set
# CONFIG_IP_ROUTE_MULTIPATH is not set
# CONFIG_IP_ROUTE_VERBOSE is not set
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MSI_IOMMU=y
CONFIG_IRQ_WORK=y
# CONFIG_ISDN is not set
CONFIG_JBD2=y
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_SUMMARY is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_KALLSYMS=y
CONFIG_LEGACY_DIRECT_IO=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=8
CONFIG_LIBCRC32C=y
CONFIG_LIBFDT=y
CONFIG_LOCALVERSION_AUTO=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_LRU_GEN is not set
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
# CONFIG_MEDIATEK_GE_SOC_PHY is not set
# CONFIG_MEMCG is not set
CONFIG_MFD_SYSCON=y
CONFIG_MIGRATION=y
CONFIG_MMU_LAZY_TLB_REFCOUNT=y
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_MQ_IOSCHED_DEADLINE=y
CONFIG_MQ_IOSCHED_KYBER=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
# CONFIG_MTD_CFI_AMDSTD is not set
CONFIG_MTD_CFI_GEOMETRY=y
# CONFIG_MTD_CFI_INTELEXT is not set
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_MTK_BMT=y
CONFIG_MTD_OF_PARTS_AIROHA=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIRMWARE_NAME="tclinux"
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_SPLIT_LZMA_FW=y
# CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NAMESPACES=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_FLAGS=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NET_AIROHA=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_MT7530=y
CONFIG_NET_DSA_MT7530_MDIO=y
CONFIG_NET_DSA_MT7530_MMIO=y
CONFIG_NET_DSA_TAG_MTK=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_KEY=y
CONFIG_NET_KEY_MIGRATE=y
# CONFIG_NET_MEDIATEK_SOC is not set
CONFIG_NET_NS=y
# CONFIG_NET_SCHED is not set
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_NTFS_DEBUG=y
CONFIG_NTFS_FS=y
CONFIG_NTFS_RW=y
CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IOMMU=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
# CONFIG_OVERLAY_FS_XINO_AUTO is not set
CONFIG_PAGE_POOL=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
# CONFIG_PANIC_ON_OOPS is not set
CONFIG_PANIC_ON_OOPS_VALUE=0
CONFIG_PANIC_TIMEOUT=0
CONFIG_PARTITION_PERCPU=y
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEASPM=y
# CONFIG_PCIEASPM_DEFAULT is not set
CONFIG_PCIEASPM_PERFORMANCE=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
CONFIG_PCIEPORTBUS=y
# CONFIG_PCIE_MEDIATEK is not set
CONFIG_PCIE_PME=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_MSI=y
CONFIG_PCPU_DEV_REFCNT=y
CONFIG_PCS_MTK_LYNXI=y
CONFIG_PERF_EVENTS=y
CONFIG_PER_VMA_LOCK=y
CONFIG_PGTABLE_LEVELS=3
CONFIG_PHYLIB=y
CONFIG_PHYLIB_LEDS=y
CONFIG_PHYLINK=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_PHY_AIROHA_PCIE=y
CONFIG_PID_NS=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_AIROHA=y
# CONFIG_PINCTRL_MT2712 is not set
# CONFIG_PINCTRL_MT6765 is not set
# CONFIG_PINCTRL_MT6795 is not set
# CONFIG_PINCTRL_MT6797 is not set
# CONFIG_PINCTRL_MT7622 is not set
# CONFIG_PINCTRL_MT7981 is not set
# CONFIG_PINCTRL_MT7986 is not set
# CONFIG_PINCTRL_MT8173 is not set
# CONFIG_PINCTRL_MT8183 is not set
# CONFIG_PINCTRL_MT8186 is not set
# CONFIG_PINCTRL_MT8188 is not set
# CONFIG_PINCTRL_MT8516 is not set
CONFIG_PM=y
CONFIG_PM_CLK=y
CONFIG_PM_OPP=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_POWER_SUPPLY=y
CONFIG_PREEMPT_NONE_BUILD=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QCOM_FALKOR_ERRATUM_1003=y
CONFIG_QCOM_FALKOR_ERRATUM_1009=y
CONFIG_QCOM_FALKOR_ERRATUM_E1041=y
CONFIG_QCOM_QDF2400_ERRATUM_0065=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RANDSTRUCT_NONE=y
CONFIG_RAS=y
CONFIG_RATIONAL=y
CONFIG_RCU_CPU_STALL_TIMEOUT=21
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RELOCATABLE=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
CONFIG_RPS=y
CONFIG_RSEQ=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
# CONFIG_SCHED_CORE is not set
CONFIG_SCHED_DEBUG=y
CONFIG_SCHED_MM_CID=y
CONFIG_SCHED_SMT=y
# CONFIG_SCHED_STACK_END_CHECK is not set
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
# CONFIG_SECURITY_DMESG_RESTRICT is not set
# CONFIG_SECURITY_NETWORK is not set
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_FSL=y
CONFIG_SERIAL_8250_NR_UARTS=5
CONFIG_SERIAL_8250_RUNTIME_UARTS=5
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIO=y
CONFIG_SERIO_LIBPS2=y
CONFIG_SGETMASK_SYSCALL=y
CONFIG_SGL_ALLOC=y
CONFIG_SKB_EXTENSIONS=y
# CONFIG_SLAB_FREELIST_HARDENED is not set
# CONFIG_SLAB_FREELIST_RANDOM is not set
CONFIG_SLUB_DEBUG=y
CONFIG_SMP=y
CONFIG_SOCIONEXT_SYNQUACER_PREITS=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SOC_BUS=y
CONFIG_SOFTIRQ_ON_OWN_STACK=y
CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
# CONFIG_SPI_AIROHA_EN7523 is not set
CONFIG_SPI_AIROHA_SNFI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
# CONFIG_SQUASHFS_EMBEDDED is not set
CONFIG_SQUASHFS_FILE_CACHE=y
# CONFIG_SQUASHFS_FILE_DIRECT is not set
CONFIG_SQUASHFS_ZLIB=y
CONFIG_STACKDEPOT=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_PER_TASK=y
CONFIG_STACKPROTECTOR_STRONG=y
CONFIG_STACKTRACE=y
# CONFIG_STAGING is not set
# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_SURFACE_PLATFORMS=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SWAP is not set
CONFIG_SWIOTLB=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYSFS_SYSCALL=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_MD5SIG=y
CONFIG_TEXTSEARCH_BM=y
CONFIG_TEXTSEARCH_FSM=y
CONFIG_TEXTSEARCH_KMP=y
CONFIG_THERMAL=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_USER_SPACE=y
CONFIG_THERMAL_OF=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_THREAD_INFO_IN_TASK=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TIME_NS=y
# CONFIG_TMPFS_XATTR is not set
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UEVENT_HELPER_PATH=""
CONFIG_UNMAP_KERNEL_AT_EL0=y
CONFIG_USELIB=y
CONFIG_USER_NS=y
CONFIG_UTS_NS=y
CONFIG_VFAT_FS=y
CONFIG_VMAP_STACK=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_WLAN is not set
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
CONFIG_XFRM_AH=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_ESP=y
CONFIG_XFRM_IPCOMP=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XPS=y
CONFIG_XXHASH=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_ARMTHUMB=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_XZ_DEC_IA64=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_SPARC=y
CONFIG_XZ_DEC_X86=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA32=y
CONFIG_ZSTD_COMMON=y
CONFIG_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y

View File

@ -0,0 +1,11 @@
ARCH:=aarch64
SUBTARGET:=en7581
BOARDNAME:=EN7581
CPU_TYPE:=cortex-a53
KERNELNAME:=Image dtbs
FEATURES+=pwm source-only
define Target/Description
Build firmware images for Airoha en7581 ARM based boards.
endef

View File

@ -0,0 +1,27 @@
define Device/FitImageLzma
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
KERNEL_NAME := Image
endef
define Device/airoha_en7581-evb
$(call Device/FitImageLzma)
DEVICE_VENDOR := Airoha
DEVICE_MODEL := EN7581 Evaluation Board (SNAND)
DEVICE_PACKAGES := kmod-leds-pwm kmod-i2c-en7581 kmod-pwm-airoha kmod-input-gpio-keys-polled
DEVICE_DTS := en7581-evb
DEVICE_DTS_DIR := ../dts
DEVICE_DTS_CONFIG := config@1
KERNEL_LOADADDR := 0x80088000
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | pad-rootfs | append-metadata
endef
TARGET_DEVICES += airoha_en7581-evb
define Device/airoha_en7581-evb-emmc
DEVICE_VENDOR := Airoha
DEVICE_MODEL := EN7581 Evaluation Board (EMMC)
DEVICE_DTS := en7581-evb-emmc
DEVICE_DTS_DIR := ../dts
DEVICE_PACKAGES := kmod-i2c-en7581
endef
TARGET_DEVICES += airoha_en7581-evb-emmc

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0-only
OTHER_MENU:=Other modules
I2C_MT7621_MODULES:= \
CONFIG_I2C_MT7621:drivers/i2c/busses/i2c-mt7621
define KernelPackage/i2c-en7581
SUBMENU:=$(OTHER_MENU)
$(call i2c_defaults,$(I2C_MT7621_MODULES),79)
TITLE:=Airoha I2C Controller
DEPENDS:=+kmod-i2c-core \
@(TARGET_airoha_en7581)
endef
define KernelPackage/i2c-en7581/description
Kernel modules for enable mt7621 i2c controller.
endef
$(eval $(call KernelPackage,i2c-en7581))
define KernelPackage/pwm-en7581
SUBMENU:=$(OTHER_MENU)
TITLE:=Airoha EN7581 PWM
DEPENDS:=@(TARGET_airoha_en7581)
KCONFIG:= \
CONFIG_PWM=y \
CONFIG_PWM_AIROHA=y \
CONFIG_PWM_SYSFS=y
FILES:= \
$(LINUX_DIR)/drivers/pwm/pwm-airoha.ko
AUTOLOAD:=$(call AutoProbe,pwm-airoha)
endef
define KernelPackage/pwm-en7581/description
Kernel module to use the PWM channel on Airoha SoC
endef
$(eval $(call KernelPackage,pwm-en7581))

View File

@ -0,0 +1,34 @@
From 428ae88ef519f2009fac37563de76ffa6f93046f Mon Sep 17 00:00:00 2001
From: Daniel Danzberger <dd@embedd.com>
Date: Sat, 9 Mar 2024 10:32:16 +0100
Subject: [PATCH] arm64: add Airoha EN7581 platform
Introduce the Kconfig entry for the Airoha EN7581 multicore architecture
available in the Airoha EN7581 evaluation board.
Signed-off-by: Daniel Danzberger <dd@embedd.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/d52d95db313e6a58ba997ba2181faf78a1014bcc.1709975956.git.lorenzo@kernel.org
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/Kconfig.platforms | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -8,6 +8,13 @@ config ARCH_ACTIONS
help
This enables support for the Actions Semiconductor S900 SoC family.
+config ARCH_AIROHA
+ bool "Airoha SoC Support"
+ select ARM_PSCI
+ select HAVE_ARM_ARCH_TIMER
+ help
+ This enables support for the ARM64 based Airoha SoCs.
+
config ARCH_SUNXI
bool "Allwinner sunxi 64-bit SoC Family"
select ARCH_HAS_RESET_CONTROLLER

View File

@ -0,0 +1,27 @@
From fd6acb0d21b8683fd8804129beeb4fe629488aff Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 9 Jul 2024 00:42:38 +0200
Subject: [PATCH] i2c: mt7621: Add Airoha EN7581 i2c support
Introduce i2c support to Airoha EN7581 SoC through the i2c-mt7621
driver.
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Ray Liu <ray.liu@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
drivers/i2c/busses/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -839,7 +839,7 @@ config I2C_MT65XX
config I2C_MT7621
tristate "MT7621/MT7628 I2C Controller"
- depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || COMPILE_TEST
+ depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || ARCH_AIROHA || COMPILE_TEST
help
Say Y here to include support for I2C controller in the
MediaTek MT7621/MT7628 SoCs.

View File

@ -0,0 +1,46 @@
From 1f038d5897fe6b439039fc28420842abcc0d126b Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 17 Jul 2024 10:15:46 +0200
Subject: [PATCH] net: airoha: fix error branch in airoha_dev_xmit and
airoha_set_gdm_ports
Fix error case management in airoha_dev_xmit routine since we need to
DMA unmap pending buffers starting from q->head.
Moreover fix a typo in error case branch in airoha_set_gdm_ports
routine.
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/b628871bc8ae4861b5e2ab4db90aaf373cbb7cee.1721203880.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -977,7 +977,7 @@ static int airoha_set_gdm_ports(struct a
return 0;
error:
- for (i--; i >= 0; i++)
+ for (i--; i >= 0; i--)
airoha_set_gdm_port(eth, port_list[i], false);
return err;
@@ -2432,9 +2432,11 @@ static netdev_tx_t airoha_dev_xmit(struc
return NETDEV_TX_OK;
error_unmap:
- for (i--; i >= 0; i++)
- dma_unmap_single(dev->dev.parent, q->entry[i].dma_addr,
- q->entry[i].dma_len, DMA_TO_DEVICE);
+ for (i--; i >= 0; i--) {
+ index = (q->head + i) % q->ndesc;
+ dma_unmap_single(dev->dev.parent, q->entry[index].dma_addr,
+ q->entry[index].dma_len, DMA_TO_DEVICE);
+ }
spin_unlock_bh(&q->lock);
error:

View File

@ -0,0 +1,39 @@
From 4e076ff6ad5302c015617da30d877b4cdcbdf613 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 17 Jul 2024 10:47:19 +0200
Subject: [PATCH] net: airoha: Fix NULL pointer dereference in
airoha_qdma_cleanup_rx_queue()
Move page_pool_get_dma_dir() inside the while loop of
airoha_qdma_cleanup_rx_queue routine in order to avoid possible NULL
pointer dereference if airoha_qdma_init_rx_queue() fails before
properly allocating the page_pool pointer.
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/7330a41bba720c33abc039955f6172457a3a34f0.1721205981.git.lorenzo@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -1586,7 +1586,6 @@ static int airoha_qdma_init_rx_queue(str
static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
{
- enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
struct airoha_eth *eth = q->eth;
while (q->queued) {
@@ -1594,7 +1593,7 @@ static void airoha_qdma_cleanup_rx_queue
struct page *page = virt_to_head_page(e->buf);
dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
- dir);
+ page_pool_get_dma_dir(q->page_pool));
page_pool_put_full_page(q->page_pool, page, false);
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;

View File

@ -0,0 +1,27 @@
From 39a9c25bcdfb5e88995841c47439b74cac74a527 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Fri, 19 Jul 2024 22:38:31 +0200
Subject: [PATCH] net: airoha: Fix MBI_RX_AGE_SEL_MASK definition
Fix copy-paste error in MBI_RX_AGE_SEL_MASK macro definition
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/d27d0465be1bff3369e886e5f10c4d37fefc4934.1721419930.git.lorenzo@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -249,7 +249,7 @@
#define REG_FE_GDM_RX_ETH_L1023_CNT_H(_n) (GDM_BASE(_n) + 0x2fc)
#define REG_GDM2_CHN_RLS (GDM2_BASE + 0x20)
-#define MBI_RX_AGE_SEL_MASK GENMASK(18, 17)
+#define MBI_RX_AGE_SEL_MASK GENMASK(26, 25)
#define MBI_TX_AGE_SEL_MASK GENMASK(18, 17)
#define REG_GDM3_FWD_CFG GDM3_BASE

View File

@ -0,0 +1,553 @@
From 16874d1cf3818a5804cded8eaff634122b1d6c7c Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:03 +0200
Subject: [PATCH 1/8] net: airoha: Introduce airoha_qdma struct
Introduce airoha_qdma struct and move qdma IO register mapping in
airoha_qdma. This is a preliminary patch to enable both QDMA controllers
available on EN7581 SoC.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/7df163bdc72ee29c3d27a0cbf54522ffeeafe53c.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 197 ++++++++++++---------
1 file changed, 112 insertions(+), 85 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -18,6 +18,7 @@
#include <uapi/linux/ppp_defs.h>
#define AIROHA_MAX_NUM_GDM_PORTS 1
+#define AIROHA_MAX_NUM_QDMA 1
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_NUM_XSI_RSTS 5
#define AIROHA_MAX_MTU 2000
@@ -782,6 +783,10 @@ struct airoha_hw_stats {
u64 rx_len[7];
};
+struct airoha_qdma {
+ void __iomem *regs;
+};
+
struct airoha_gdm_port {
struct net_device *dev;
struct airoha_eth *eth;
@@ -794,8 +799,6 @@ struct airoha_eth {
struct device *dev;
unsigned long state;
-
- void __iomem *qdma_regs;
void __iomem *fe_regs;
/* protect concurrent irqmask accesses */
@@ -806,6 +809,7 @@ struct airoha_eth {
struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
+ struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
struct net_device *napi_dev;
@@ -850,16 +854,16 @@ static u32 airoha_rmw(void __iomem *base
#define airoha_fe_clear(eth, offset, val) \
airoha_rmw((eth)->fe_regs, (offset), (val), 0)
-#define airoha_qdma_rr(eth, offset) \
- airoha_rr((eth)->qdma_regs, (offset))
-#define airoha_qdma_wr(eth, offset, val) \
- airoha_wr((eth)->qdma_regs, (offset), (val))
-#define airoha_qdma_rmw(eth, offset, mask, val) \
- airoha_rmw((eth)->qdma_regs, (offset), (mask), (val))
-#define airoha_qdma_set(eth, offset, val) \
- airoha_rmw((eth)->qdma_regs, (offset), 0, (val))
-#define airoha_qdma_clear(eth, offset, val) \
- airoha_rmw((eth)->qdma_regs, (offset), (val), 0)
+#define airoha_qdma_rr(qdma, offset) \
+ airoha_rr((qdma)->regs, (offset))
+#define airoha_qdma_wr(qdma, offset, val) \
+ airoha_wr((qdma)->regs, (offset), (val))
+#define airoha_qdma_rmw(qdma, offset, mask, val) \
+ airoha_rmw((qdma)->regs, (offset), (mask), (val))
+#define airoha_qdma_set(qdma, offset, val) \
+ airoha_rmw((qdma)->regs, (offset), 0, (val))
+#define airoha_qdma_clear(qdma, offset, val) \
+ airoha_rmw((qdma)->regs, (offset), (val), 0)
static void airoha_qdma_set_irqmask(struct airoha_eth *eth, int index,
u32 clear, u32 set)
@@ -873,11 +877,12 @@ static void airoha_qdma_set_irqmask(stru
eth->irqmask[index] &= ~clear;
eth->irqmask[index] |= set;
- airoha_qdma_wr(eth, REG_INT_ENABLE(index), eth->irqmask[index]);
+ airoha_qdma_wr(&eth->qdma[0], REG_INT_ENABLE(index),
+ eth->irqmask[index]);
/* Read irq_enable register in order to guarantee the update above
* completes in the spinlock critical section.
*/
- airoha_qdma_rr(eth, REG_INT_ENABLE(index));
+ airoha_qdma_rr(&eth->qdma[0], REG_INT_ENABLE(index));
spin_unlock_irqrestore(&eth->irq_lock, flags);
}
@@ -1383,6 +1388,7 @@ static int airoha_fe_init(struct airoha_
static int airoha_qdma_fill_rx_queue(struct airoha_queue *q)
{
enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
+ struct airoha_qdma *qdma = &q->eth->qdma[0];
struct airoha_eth *eth = q->eth;
int qid = q - &eth->q_rx[0];
int nframes = 0;
@@ -1420,7 +1426,8 @@ static int airoha_qdma_fill_rx_queue(str
WRITE_ONCE(desc->msg2, 0);
WRITE_ONCE(desc->msg3, 0);
- airoha_qdma_rmw(eth, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid),
+ RX_RING_CPU_IDX_MASK,
FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
}
@@ -1529,7 +1536,8 @@ static int airoha_qdma_rx_napi_poll(stru
}
static int airoha_qdma_init_rx_queue(struct airoha_eth *eth,
- struct airoha_queue *q, int ndesc)
+ struct airoha_queue *q,
+ struct airoha_qdma *qdma, int ndesc)
{
const struct page_pool_params pp_params = {
.order = 0,
@@ -1569,14 +1577,15 @@ static int airoha_qdma_init_rx_queue(str
netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
- airoha_qdma_wr(eth, REG_RX_RING_BASE(qid), dma_addr);
- airoha_qdma_rmw(eth, REG_RX_RING_SIZE(qid), RX_RING_SIZE_MASK,
+ airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
+ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid),
+ RX_RING_SIZE_MASK,
FIELD_PREP(RX_RING_SIZE_MASK, ndesc));
thr = clamp(ndesc >> 3, 1, 32);
- airoha_qdma_rmw(eth, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK,
+ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK,
FIELD_PREP(RX_RING_THR_MASK, thr));
- airoha_qdma_rmw(eth, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head));
airoha_qdma_fill_rx_queue(q);
@@ -1600,7 +1609,8 @@ static void airoha_qdma_cleanup_rx_queue
}
}
-static int airoha_qdma_init_rx(struct airoha_eth *eth)
+static int airoha_qdma_init_rx(struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
int i;
@@ -1613,7 +1623,7 @@ static int airoha_qdma_init_rx(struct ai
}
err = airoha_qdma_init_rx_queue(eth, &eth->q_rx[i],
- RX_DSCP_NUM(i));
+ qdma, RX_DSCP_NUM(i));
if (err)
return err;
}
@@ -1624,11 +1634,13 @@ static int airoha_qdma_init_rx(struct ai
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
+ struct airoha_qdma *qdma;
struct airoha_eth *eth;
int id, done = 0;
irq_q = container_of(napi, struct airoha_tx_irq_queue, napi);
eth = irq_q->eth;
+ qdma = &eth->qdma[0];
id = irq_q - &eth->q_tx_irq[0];
while (irq_q->queued > 0 && done < budget) {
@@ -1698,9 +1710,9 @@ static int airoha_qdma_tx_napi_poll(stru
int i, len = done >> 7;
for (i = 0; i < len; i++)
- airoha_qdma_rmw(eth, REG_IRQ_CLEAR_LEN(id),
+ airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id),
IRQ_CLEAR_LEN_MASK, 0x80);
- airoha_qdma_rmw(eth, REG_IRQ_CLEAR_LEN(id),
+ airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id),
IRQ_CLEAR_LEN_MASK, (done & 0x7f));
}
@@ -1712,7 +1724,8 @@ static int airoha_qdma_tx_napi_poll(stru
}
static int airoha_qdma_init_tx_queue(struct airoha_eth *eth,
- struct airoha_queue *q, int size)
+ struct airoha_queue *q,
+ struct airoha_qdma *qdma, int size)
{
int i, qid = q - &eth->q_tx[0];
dma_addr_t dma_addr;
@@ -1739,10 +1752,10 @@ static int airoha_qdma_init_tx_queue(str
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
}
- airoha_qdma_wr(eth, REG_TX_RING_BASE(qid), dma_addr);
- airoha_qdma_rmw(eth, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr);
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
- airoha_qdma_rmw(eth, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head));
return 0;
@@ -1750,7 +1763,7 @@ static int airoha_qdma_init_tx_queue(str
static int airoha_qdma_tx_irq_init(struct airoha_eth *eth,
struct airoha_tx_irq_queue *irq_q,
- int size)
+ struct airoha_qdma *qdma, int size)
{
int id = irq_q - &eth->q_tx_irq[0];
dma_addr_t dma_addr;
@@ -1766,29 +1779,30 @@ static int airoha_qdma_tx_irq_init(struc
irq_q->size = size;
irq_q->eth = eth;
- airoha_qdma_wr(eth, REG_TX_IRQ_BASE(id), dma_addr);
- airoha_qdma_rmw(eth, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
+ airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr);
+ airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
FIELD_PREP(TX_IRQ_DEPTH_MASK, size));
- airoha_qdma_rmw(eth, REG_TX_IRQ_CFG(id), TX_IRQ_THR_MASK,
+ airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_THR_MASK,
FIELD_PREP(TX_IRQ_THR_MASK, 1));
return 0;
}
-static int airoha_qdma_init_tx(struct airoha_eth *eth)
+static int airoha_qdma_init_tx(struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
int i, err;
for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) {
err = airoha_qdma_tx_irq_init(eth, &eth->q_tx_irq[i],
- IRQ_QUEUE_LEN(i));
+ qdma, IRQ_QUEUE_LEN(i));
if (err)
return err;
}
for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) {
err = airoha_qdma_init_tx_queue(eth, &eth->q_tx[i],
- TX_DSCP_NUM);
+ qdma, TX_DSCP_NUM);
if (err)
return err;
}
@@ -1815,7 +1829,8 @@ static void airoha_qdma_cleanup_tx_queue
spin_unlock_bh(&q->lock);
}
-static int airoha_qdma_init_hfwd_queues(struct airoha_eth *eth)
+static int airoha_qdma_init_hfwd_queues(struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
dma_addr_t dma_addr;
u32 status;
@@ -1827,7 +1842,7 @@ static int airoha_qdma_init_hfwd_queues(
if (!eth->hfwd.desc)
return -ENOMEM;
- airoha_qdma_wr(eth, REG_FWD_DSCP_BASE, dma_addr);
+ airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM;
eth->hfwd.q = dmam_alloc_coherent(eth->dev, size, &dma_addr,
@@ -1835,14 +1850,14 @@ static int airoha_qdma_init_hfwd_queues(
if (!eth->hfwd.q)
return -ENOMEM;
- airoha_qdma_wr(eth, REG_FWD_BUF_BASE, dma_addr);
+ airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr);
- airoha_qdma_rmw(eth, REG_HW_FWD_DSCP_CFG,
+ airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG,
HW_FWD_DSCP_PAYLOAD_SIZE_MASK,
FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, 0));
- airoha_qdma_rmw(eth, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK,
+ airoha_qdma_rmw(qdma, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK,
FIELD_PREP(FWD_DSCP_LOW_THR_MASK, 128));
- airoha_qdma_rmw(eth, REG_LMGR_INIT_CFG,
+ airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
HW_FWD_DESC_NUM_MASK,
FIELD_PREP(HW_FWD_DESC_NUM_MASK, HW_DSCP_NUM) |
@@ -1850,67 +1865,69 @@ static int airoha_qdma_init_hfwd_queues(
return read_poll_timeout(airoha_qdma_rr, status,
!(status & LMGR_INIT_START), USEC_PER_MSEC,
- 30 * USEC_PER_MSEC, true, eth,
+ 30 * USEC_PER_MSEC, true, qdma,
REG_LMGR_INIT_CFG);
}
-static void airoha_qdma_init_qos(struct airoha_eth *eth)
+static void airoha_qdma_init_qos(struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
- airoha_qdma_clear(eth, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_SCALE_MASK);
- airoha_qdma_set(eth, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_BASE_MASK);
+ airoha_qdma_clear(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_SCALE_MASK);
+ airoha_qdma_set(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_BASE_MASK);
- airoha_qdma_clear(eth, REG_PSE_BUF_USAGE_CFG,
+ airoha_qdma_clear(qdma, REG_PSE_BUF_USAGE_CFG,
PSE_BUF_ESTIMATE_EN_MASK);
- airoha_qdma_set(eth, REG_EGRESS_RATE_METER_CFG,
+ airoha_qdma_set(qdma, REG_EGRESS_RATE_METER_CFG,
EGRESS_RATE_METER_EN_MASK |
EGRESS_RATE_METER_EQ_RATE_EN_MASK);
/* 2047us x 31 = 63.457ms */
- airoha_qdma_rmw(eth, REG_EGRESS_RATE_METER_CFG,
+ airoha_qdma_rmw(qdma, REG_EGRESS_RATE_METER_CFG,
EGRESS_RATE_METER_WINDOW_SZ_MASK,
FIELD_PREP(EGRESS_RATE_METER_WINDOW_SZ_MASK, 0x1f));
- airoha_qdma_rmw(eth, REG_EGRESS_RATE_METER_CFG,
+ airoha_qdma_rmw(qdma, REG_EGRESS_RATE_METER_CFG,
EGRESS_RATE_METER_TIMESLICE_MASK,
FIELD_PREP(EGRESS_RATE_METER_TIMESLICE_MASK, 0x7ff));
/* ratelimit init */
- airoha_qdma_set(eth, REG_GLB_TRTCM_CFG, GLB_TRTCM_EN_MASK);
+ airoha_qdma_set(qdma, REG_GLB_TRTCM_CFG, GLB_TRTCM_EN_MASK);
/* fast-tick 25us */
- airoha_qdma_rmw(eth, REG_GLB_TRTCM_CFG, GLB_FAST_TICK_MASK,
+ airoha_qdma_rmw(qdma, REG_GLB_TRTCM_CFG, GLB_FAST_TICK_MASK,
FIELD_PREP(GLB_FAST_TICK_MASK, 25));
- airoha_qdma_rmw(eth, REG_GLB_TRTCM_CFG, GLB_SLOW_TICK_RATIO_MASK,
+ airoha_qdma_rmw(qdma, REG_GLB_TRTCM_CFG, GLB_SLOW_TICK_RATIO_MASK,
FIELD_PREP(GLB_SLOW_TICK_RATIO_MASK, 40));
- airoha_qdma_set(eth, REG_EGRESS_TRTCM_CFG, EGRESS_TRTCM_EN_MASK);
- airoha_qdma_rmw(eth, REG_EGRESS_TRTCM_CFG, EGRESS_FAST_TICK_MASK,
+ airoha_qdma_set(qdma, REG_EGRESS_TRTCM_CFG, EGRESS_TRTCM_EN_MASK);
+ airoha_qdma_rmw(qdma, REG_EGRESS_TRTCM_CFG, EGRESS_FAST_TICK_MASK,
FIELD_PREP(EGRESS_FAST_TICK_MASK, 25));
- airoha_qdma_rmw(eth, REG_EGRESS_TRTCM_CFG,
+ airoha_qdma_rmw(qdma, REG_EGRESS_TRTCM_CFG,
EGRESS_SLOW_TICK_RATIO_MASK,
FIELD_PREP(EGRESS_SLOW_TICK_RATIO_MASK, 40));
- airoha_qdma_set(eth, REG_INGRESS_TRTCM_CFG, INGRESS_TRTCM_EN_MASK);
- airoha_qdma_clear(eth, REG_INGRESS_TRTCM_CFG,
+ airoha_qdma_set(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_TRTCM_EN_MASK);
+ airoha_qdma_clear(qdma, REG_INGRESS_TRTCM_CFG,
INGRESS_TRTCM_MODE_MASK);
- airoha_qdma_rmw(eth, REG_INGRESS_TRTCM_CFG, INGRESS_FAST_TICK_MASK,
+ airoha_qdma_rmw(qdma, REG_INGRESS_TRTCM_CFG, INGRESS_FAST_TICK_MASK,
FIELD_PREP(INGRESS_FAST_TICK_MASK, 125));
- airoha_qdma_rmw(eth, REG_INGRESS_TRTCM_CFG,
+ airoha_qdma_rmw(qdma, REG_INGRESS_TRTCM_CFG,
INGRESS_SLOW_TICK_RATIO_MASK,
FIELD_PREP(INGRESS_SLOW_TICK_RATIO_MASK, 8));
- airoha_qdma_set(eth, REG_SLA_TRTCM_CFG, SLA_TRTCM_EN_MASK);
- airoha_qdma_rmw(eth, REG_SLA_TRTCM_CFG, SLA_FAST_TICK_MASK,
+ airoha_qdma_set(qdma, REG_SLA_TRTCM_CFG, SLA_TRTCM_EN_MASK);
+ airoha_qdma_rmw(qdma, REG_SLA_TRTCM_CFG, SLA_FAST_TICK_MASK,
FIELD_PREP(SLA_FAST_TICK_MASK, 25));
- airoha_qdma_rmw(eth, REG_SLA_TRTCM_CFG, SLA_SLOW_TICK_RATIO_MASK,
+ airoha_qdma_rmw(qdma, REG_SLA_TRTCM_CFG, SLA_SLOW_TICK_RATIO_MASK,
FIELD_PREP(SLA_SLOW_TICK_RATIO_MASK, 40));
}
-static int airoha_qdma_hw_init(struct airoha_eth *eth)
+static int airoha_qdma_hw_init(struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
int i;
/* clear pending irqs */
for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++)
- airoha_qdma_wr(eth, REG_INT_STATUS(i), 0xffffffff);
+ airoha_qdma_wr(qdma, REG_INT_STATUS(i), 0xffffffff);
/* setup irqs */
airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX0, INT_IDX0_MASK);
@@ -1923,14 +1940,14 @@ static int airoha_qdma_hw_init(struct ai
continue;
if (TX_RING_IRQ_BLOCKING_MAP_MASK & BIT(i))
- airoha_qdma_set(eth, REG_TX_RING_BLOCKING(i),
+ airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(i),
TX_RING_IRQ_BLOCKING_CFG_MASK);
else
- airoha_qdma_clear(eth, REG_TX_RING_BLOCKING(i),
+ airoha_qdma_clear(qdma, REG_TX_RING_BLOCKING(i),
TX_RING_IRQ_BLOCKING_CFG_MASK);
}
- airoha_qdma_wr(eth, REG_QDMA_GLOBAL_CFG,
+ airoha_qdma_wr(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_RX_2B_OFFSET_MASK |
FIELD_PREP(GLOBAL_CFG_DMA_PREFERENCE_MASK, 3) |
GLOBAL_CFG_CPU_TXR_RR_MASK |
@@ -1941,18 +1958,18 @@ static int airoha_qdma_hw_init(struct ai
GLOBAL_CFG_TX_WB_DONE_MASK |
FIELD_PREP(GLOBAL_CFG_MAX_ISSUE_NUM_MASK, 2));
- airoha_qdma_init_qos(eth);
+ airoha_qdma_init_qos(eth, qdma);
/* disable qdma rx delay interrupt */
for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
if (!eth->q_rx[i].ndesc)
continue;
- airoha_qdma_clear(eth, REG_RX_DELAY_INT_IDX(i),
+ airoha_qdma_clear(qdma, REG_RX_DELAY_INT_IDX(i),
RX_DELAY_INT_MASK);
}
- airoha_qdma_set(eth, REG_TXQ_CNGST_CFG,
+ airoha_qdma_set(qdma, REG_TXQ_CNGST_CFG,
TXQ_CNGST_DROP_EN | TXQ_CNGST_DEI_DROP_EN);
return 0;
@@ -1962,12 +1979,14 @@ static irqreturn_t airoha_irq_handler(in
{
struct airoha_eth *eth = dev_instance;
u32 intr[ARRAY_SIZE(eth->irqmask)];
+ struct airoha_qdma *qdma;
int i;
+ qdma = &eth->qdma[0];
for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++) {
- intr[i] = airoha_qdma_rr(eth, REG_INT_STATUS(i));
+ intr[i] = airoha_qdma_rr(qdma, REG_INT_STATUS(i));
intr[i] &= eth->irqmask[i];
- airoha_qdma_wr(eth, REG_INT_STATUS(i), intr[i]);
+ airoha_qdma_wr(qdma, REG_INT_STATUS(i), intr[i]);
}
if (!test_bit(DEV_STATE_INITIALIZED, &eth->state))
@@ -1997,7 +2016,7 @@ static irqreturn_t airoha_irq_handler(in
airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX0,
TX_DONE_INT_MASK(i));
- status = airoha_qdma_rr(eth, REG_IRQ_STATUS(i));
+ status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(i));
head = FIELD_GET(IRQ_HEAD_IDX_MASK, status);
irq_q->head = head % irq_q->size;
irq_q->queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status);
@@ -2011,6 +2030,7 @@ static irqreturn_t airoha_irq_handler(in
static int airoha_qdma_init(struct airoha_eth *eth)
{
+ struct airoha_qdma *qdma = &eth->qdma[0];
int err;
err = devm_request_irq(eth->dev, eth->irq, airoha_irq_handler,
@@ -2018,19 +2038,19 @@ static int airoha_qdma_init(struct airoh
if (err)
return err;
- err = airoha_qdma_init_rx(eth);
+ err = airoha_qdma_init_rx(eth, qdma);
if (err)
return err;
- err = airoha_qdma_init_tx(eth);
+ err = airoha_qdma_init_tx(eth, qdma);
if (err)
return err;
- err = airoha_qdma_init_hfwd_queues(eth);
+ err = airoha_qdma_init_hfwd_queues(eth, qdma);
if (err)
return err;
- err = airoha_qdma_hw_init(eth);
+ err = airoha_qdma_hw_init(eth, qdma);
if (err)
return err;
@@ -2263,8 +2283,9 @@ static int airoha_dev_open(struct net_de
airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
- airoha_qdma_set(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_TX_DMA_EN_MASK);
- airoha_qdma_set(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_RX_DMA_EN_MASK);
+ airoha_qdma_set(&eth->qdma[0], REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
return 0;
}
@@ -2280,8 +2301,9 @@ static int airoha_dev_stop(struct net_de
if (err)
return err;
- airoha_qdma_clear(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_TX_DMA_EN_MASK);
- airoha_qdma_clear(eth, REG_QDMA_GLOBAL_CFG, GLOBAL_CFG_RX_DMA_EN_MASK);
+ airoha_qdma_clear(&eth->qdma[0], REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
return 0;
}
@@ -2341,6 +2363,7 @@ static netdev_tx_t airoha_dev_xmit(struc
struct airoha_eth *eth = port->eth;
u32 nr_frags = 1 + sinfo->nr_frags;
struct netdev_queue *txq;
+ struct airoha_qdma *qdma;
struct airoha_queue *q;
void *data = skb->data;
u16 index;
@@ -2368,6 +2391,7 @@ static netdev_tx_t airoha_dev_xmit(struc
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
+ qdma = &eth->qdma[0];
q = &eth->q_tx[qid];
if (WARN_ON_ONCE(!q->ndesc))
goto error;
@@ -2412,7 +2436,8 @@ static netdev_tx_t airoha_dev_xmit(struc
e->dma_addr = addr;
e->dma_len = len;
- airoha_qdma_rmw(eth, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
+ TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
data = skb_frag_address(frag);
@@ -2614,9 +2639,11 @@ static int airoha_probe(struct platform_
return dev_err_probe(eth->dev, PTR_ERR(eth->fe_regs),
"failed to iomap fe regs\n");
- eth->qdma_regs = devm_platform_ioremap_resource_byname(pdev, "qdma0");
- if (IS_ERR(eth->qdma_regs))
- return dev_err_probe(eth->dev, PTR_ERR(eth->qdma_regs),
+ eth->qdma[0].regs = devm_platform_ioremap_resource_byname(pdev,
+ "qdma0");
+ if (IS_ERR(eth->qdma[0].regs))
+ return dev_err_probe(eth->dev,
+ PTR_ERR(eth->qdma[0].regs),
"failed to iomap qdma regs\n");
eth->rsts[0].id = "fe";

View File

@ -0,0 +1,318 @@
From 245c7bc86b198e5ec227eba6b582da73cb0721c8 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:04 +0200
Subject: [PATCH 2/8] net: airoha: Move airoha_queues in airoha_qdma
QDMA controllers available in EN7581 SoC have independent tx/rx hw queues
so move them in airoha_queues structure.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/795fc4797bffbf7f0a1351308aa9bf0e65b5126e.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 126 +++++++++++----------
1 file changed, 65 insertions(+), 61 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -785,6 +785,17 @@ struct airoha_hw_stats {
struct airoha_qdma {
void __iomem *regs;
+
+ struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
+
+ struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
+ struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
+
+ /* descriptor and packet buffers for qdma hw forward */
+ struct {
+ void *desc;
+ void *q;
+ } hfwd;
};
struct airoha_gdm_port {
@@ -809,20 +820,10 @@ struct airoha_eth {
struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
- struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
- struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
-
struct net_device *napi_dev;
- struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
- struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
-
- struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
- /* descriptor and packet buffers for qdma hw forward */
- struct {
- void *desc;
- void *q;
- } hfwd;
+ struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
+ struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
};
static u32 airoha_rr(void __iomem *base, u32 offset)
@@ -1390,7 +1391,7 @@ static int airoha_qdma_fill_rx_queue(str
enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
struct airoha_qdma *qdma = &q->eth->qdma[0];
struct airoha_eth *eth = q->eth;
- int qid = q - &eth->q_rx[0];
+ int qid = q - &qdma->q_rx[0];
int nframes = 0;
while (q->queued < q->ndesc - 1) {
@@ -1457,8 +1458,9 @@ static int airoha_qdma_get_gdm_port(stru
static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
{
enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
+ struct airoha_qdma *qdma = &q->eth->qdma[0];
struct airoha_eth *eth = q->eth;
- int qid = q - &eth->q_rx[0];
+ int qid = q - &qdma->q_rx[0];
int done = 0;
while (done < budget) {
@@ -1550,7 +1552,7 @@ static int airoha_qdma_init_rx_queue(str
.dev = eth->dev,
.napi = &q->napi,
};
- int qid = q - &eth->q_rx[0], thr;
+ int qid = q - &qdma->q_rx[0], thr;
dma_addr_t dma_addr;
q->buf_size = PAGE_SIZE / 2;
@@ -1614,7 +1616,7 @@ static int airoha_qdma_init_rx(struct ai
{
int i;
- for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
int err;
if (!(RX_DONE_INT_MASK & BIT(i))) {
@@ -1622,7 +1624,7 @@ static int airoha_qdma_init_rx(struct ai
continue;
}
- err = airoha_qdma_init_rx_queue(eth, &eth->q_rx[i],
+ err = airoha_qdma_init_rx_queue(eth, &qdma->q_rx[i],
qdma, RX_DSCP_NUM(i));
if (err)
return err;
@@ -1641,7 +1643,7 @@ static int airoha_qdma_tx_napi_poll(stru
irq_q = container_of(napi, struct airoha_tx_irq_queue, napi);
eth = irq_q->eth;
qdma = &eth->qdma[0];
- id = irq_q - &eth->q_tx_irq[0];
+ id = irq_q - &qdma->q_tx_irq[0];
while (irq_q->queued > 0 && done < budget) {
u32 qid, last, val = irq_q->q[irq_q->head];
@@ -1658,10 +1660,10 @@ static int airoha_qdma_tx_napi_poll(stru
last = FIELD_GET(IRQ_DESC_IDX_MASK, val);
qid = FIELD_GET(IRQ_RING_IDX_MASK, val);
- if (qid >= ARRAY_SIZE(eth->q_tx))
+ if (qid >= ARRAY_SIZE(qdma->q_tx))
continue;
- q = &eth->q_tx[qid];
+ q = &qdma->q_tx[qid];
if (!q->ndesc)
continue;
@@ -1727,7 +1729,7 @@ static int airoha_qdma_init_tx_queue(str
struct airoha_queue *q,
struct airoha_qdma *qdma, int size)
{
- int i, qid = q - &eth->q_tx[0];
+ int i, qid = q - &qdma->q_tx[0];
dma_addr_t dma_addr;
spin_lock_init(&q->lock);
@@ -1765,7 +1767,7 @@ static int airoha_qdma_tx_irq_init(struc
struct airoha_tx_irq_queue *irq_q,
struct airoha_qdma *qdma, int size)
{
- int id = irq_q - &eth->q_tx_irq[0];
+ int id = irq_q - &qdma->q_tx_irq[0];
dma_addr_t dma_addr;
netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
@@ -1793,15 +1795,15 @@ static int airoha_qdma_init_tx(struct ai
{
int i, err;
- for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) {
- err = airoha_qdma_tx_irq_init(eth, &eth->q_tx_irq[i],
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+ err = airoha_qdma_tx_irq_init(eth, &qdma->q_tx_irq[i],
qdma, IRQ_QUEUE_LEN(i));
if (err)
return err;
}
- for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) {
- err = airoha_qdma_init_tx_queue(eth, &eth->q_tx[i],
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ err = airoha_qdma_init_tx_queue(eth, &qdma->q_tx[i],
qdma, TX_DSCP_NUM);
if (err)
return err;
@@ -1837,17 +1839,17 @@ static int airoha_qdma_init_hfwd_queues(
int size;
size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc);
- eth->hfwd.desc = dmam_alloc_coherent(eth->dev, size, &dma_addr,
- GFP_KERNEL);
- if (!eth->hfwd.desc)
+ qdma->hfwd.desc = dmam_alloc_coherent(eth->dev, size, &dma_addr,
+ GFP_KERNEL);
+ if (!qdma->hfwd.desc)
return -ENOMEM;
airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM;
- eth->hfwd.q = dmam_alloc_coherent(eth->dev, size, &dma_addr,
- GFP_KERNEL);
- if (!eth->hfwd.q)
+ qdma->hfwd.q = dmam_alloc_coherent(eth->dev, size, &dma_addr,
+ GFP_KERNEL);
+ if (!qdma->hfwd.q)
return -ENOMEM;
airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr);
@@ -1935,8 +1937,8 @@ static int airoha_qdma_hw_init(struct ai
airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX4, INT_IDX4_MASK);
/* setup irq binding */
- for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) {
- if (!eth->q_tx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ if (!qdma->q_tx[i].ndesc)
continue;
if (TX_RING_IRQ_BLOCKING_MAP_MASK & BIT(i))
@@ -1961,8 +1963,8 @@ static int airoha_qdma_hw_init(struct ai
airoha_qdma_init_qos(eth, qdma);
/* disable qdma rx delay interrupt */
- for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
- if (!eth->q_rx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
continue;
airoha_qdma_clear(qdma, REG_RX_DELAY_INT_IDX(i),
@@ -1996,18 +1998,18 @@ static irqreturn_t airoha_irq_handler(in
airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX1,
RX_DONE_INT_MASK);
- for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
- if (!eth->q_rx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
continue;
if (intr[1] & BIT(i))
- napi_schedule(&eth->q_rx[i].napi);
+ napi_schedule(&qdma->q_rx[i].napi);
}
}
if (intr[0] & INT_TX_MASK) {
- for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) {
- struct airoha_tx_irq_queue *irq_q = &eth->q_tx_irq[i];
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+ struct airoha_tx_irq_queue *irq_q = &qdma->q_tx_irq[i];
u32 status, head;
if (!(intr[0] & TX_DONE_INT_MASK(i)))
@@ -2021,7 +2023,7 @@ static irqreturn_t airoha_irq_handler(in
irq_q->head = head % irq_q->size;
irq_q->queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status);
- napi_schedule(&eth->q_tx_irq[i].napi);
+ napi_schedule(&qdma->q_tx_irq[i].napi);
}
}
@@ -2080,44 +2082,46 @@ static int airoha_hw_init(struct airoha_
static void airoha_hw_cleanup(struct airoha_eth *eth)
{
+ struct airoha_qdma *qdma = &eth->qdma[0];
int i;
- for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
- if (!eth->q_rx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
continue;
- napi_disable(&eth->q_rx[i].napi);
- netif_napi_del(&eth->q_rx[i].napi);
- airoha_qdma_cleanup_rx_queue(&eth->q_rx[i]);
- if (eth->q_rx[i].page_pool)
- page_pool_destroy(eth->q_rx[i].page_pool);
+ napi_disable(&qdma->q_rx[i].napi);
+ netif_napi_del(&qdma->q_rx[i].napi);
+ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
+ if (qdma->q_rx[i].page_pool)
+ page_pool_destroy(qdma->q_rx[i].page_pool);
}
- for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++) {
- napi_disable(&eth->q_tx_irq[i].napi);
- netif_napi_del(&eth->q_tx_irq[i].napi);
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+ napi_disable(&qdma->q_tx_irq[i].napi);
+ netif_napi_del(&qdma->q_tx_irq[i].napi);
}
- for (i = 0; i < ARRAY_SIZE(eth->q_tx); i++) {
- if (!eth->q_tx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ if (!qdma->q_tx[i].ndesc)
continue;
- airoha_qdma_cleanup_tx_queue(&eth->q_tx[i]);
+ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
}
}
static void airoha_qdma_start_napi(struct airoha_eth *eth)
{
+ struct airoha_qdma *qdma = &eth->qdma[0];
int i;
- for (i = 0; i < ARRAY_SIZE(eth->q_tx_irq); i++)
- napi_enable(&eth->q_tx_irq[i].napi);
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
+ napi_enable(&qdma->q_tx_irq[i].napi);
- for (i = 0; i < ARRAY_SIZE(eth->q_rx); i++) {
- if (!eth->q_rx[i].ndesc)
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
continue;
- napi_enable(&eth->q_rx[i].napi);
+ napi_enable(&qdma->q_rx[i].napi);
}
}
@@ -2392,7 +2396,7 @@ static netdev_tx_t airoha_dev_xmit(struc
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
qdma = &eth->qdma[0];
- q = &eth->q_tx[qid];
+ q = &qdma->q_tx[qid];
if (WARN_ON_ONCE(!q->ndesc))
goto error;

View File

@ -0,0 +1,236 @@
From 19e47fc2aeda3a657c4f64144ffd6e65f7a66601 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:05 +0200
Subject: [PATCH 3/8] net: airoha: Move irq_mask in airoha_qdma structure
QDMA controllers have independent irq lines, so move irqmask in
airoha_qdma structure. This is a preliminary patch to support multiple
QDMA controllers.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/1c8a06e8be605278a7b2f3cd8ac06e74bf5ebf2b.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 84 +++++++++++-----------
1 file changed, 42 insertions(+), 42 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -786,6 +786,11 @@ struct airoha_hw_stats {
struct airoha_qdma {
void __iomem *regs;
+ /* protect concurrent irqmask accesses */
+ spinlock_t irq_lock;
+ u32 irqmask[QDMA_INT_REG_MAX];
+ int irq;
+
struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
@@ -812,11 +817,6 @@ struct airoha_eth {
unsigned long state;
void __iomem *fe_regs;
- /* protect concurrent irqmask accesses */
- spinlock_t irq_lock;
- u32 irqmask[QDMA_INT_REG_MAX];
- int irq;
-
struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
@@ -866,38 +866,37 @@ static u32 airoha_rmw(void __iomem *base
#define airoha_qdma_clear(qdma, offset, val) \
airoha_rmw((qdma)->regs, (offset), (val), 0)
-static void airoha_qdma_set_irqmask(struct airoha_eth *eth, int index,
+static void airoha_qdma_set_irqmask(struct airoha_qdma *qdma, int index,
u32 clear, u32 set)
{
unsigned long flags;
- if (WARN_ON_ONCE(index >= ARRAY_SIZE(eth->irqmask)))
+ if (WARN_ON_ONCE(index >= ARRAY_SIZE(qdma->irqmask)))
return;
- spin_lock_irqsave(&eth->irq_lock, flags);
+ spin_lock_irqsave(&qdma->irq_lock, flags);
- eth->irqmask[index] &= ~clear;
- eth->irqmask[index] |= set;
- airoha_qdma_wr(&eth->qdma[0], REG_INT_ENABLE(index),
- eth->irqmask[index]);
+ qdma->irqmask[index] &= ~clear;
+ qdma->irqmask[index] |= set;
+ airoha_qdma_wr(qdma, REG_INT_ENABLE(index), qdma->irqmask[index]);
/* Read irq_enable register in order to guarantee the update above
* completes in the spinlock critical section.
*/
- airoha_qdma_rr(&eth->qdma[0], REG_INT_ENABLE(index));
+ airoha_qdma_rr(qdma, REG_INT_ENABLE(index));
- spin_unlock_irqrestore(&eth->irq_lock, flags);
+ spin_unlock_irqrestore(&qdma->irq_lock, flags);
}
-static void airoha_qdma_irq_enable(struct airoha_eth *eth, int index,
+static void airoha_qdma_irq_enable(struct airoha_qdma *qdma, int index,
u32 mask)
{
- airoha_qdma_set_irqmask(eth, index, 0, mask);
+ airoha_qdma_set_irqmask(qdma, index, 0, mask);
}
-static void airoha_qdma_irq_disable(struct airoha_eth *eth, int index,
+static void airoha_qdma_irq_disable(struct airoha_qdma *qdma, int index,
u32 mask)
{
- airoha_qdma_set_irqmask(eth, index, mask, 0);
+ airoha_qdma_set_irqmask(qdma, index, mask, 0);
}
static void airoha_set_macaddr(struct airoha_eth *eth, const u8 *addr)
@@ -1522,7 +1521,7 @@ static int airoha_qdma_rx_process(struct
static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_queue *q = container_of(napi, struct airoha_queue, napi);
- struct airoha_eth *eth = q->eth;
+ struct airoha_qdma *qdma = &q->eth->qdma[0];
int cur, done = 0;
do {
@@ -1531,7 +1530,7 @@ static int airoha_qdma_rx_napi_poll(stru
} while (cur && done < budget);
if (done < budget && napi_complete(napi))
- airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX1,
+ airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX1,
RX_DONE_INT_MASK);
return done;
@@ -1719,7 +1718,7 @@ static int airoha_qdma_tx_napi_poll(stru
}
if (done < budget && napi_complete(napi))
- airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX0,
+ airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX0,
TX_DONE_INT_MASK(id));
return done;
@@ -1928,13 +1927,13 @@ static int airoha_qdma_hw_init(struct ai
int i;
/* clear pending irqs */
- for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++)
+ for (i = 0; i < ARRAY_SIZE(qdma->irqmask); i++)
airoha_qdma_wr(qdma, REG_INT_STATUS(i), 0xffffffff);
/* setup irqs */
- airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX0, INT_IDX0_MASK);
- airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX1, INT_IDX1_MASK);
- airoha_qdma_irq_enable(eth, QDMA_INT_REG_IDX4, INT_IDX4_MASK);
+ airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX0, INT_IDX0_MASK);
+ airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX1, INT_IDX1_MASK);
+ airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX4, INT_IDX4_MASK);
/* setup irq binding */
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
@@ -1980,14 +1979,13 @@ static int airoha_qdma_hw_init(struct ai
static irqreturn_t airoha_irq_handler(int irq, void *dev_instance)
{
struct airoha_eth *eth = dev_instance;
- u32 intr[ARRAY_SIZE(eth->irqmask)];
- struct airoha_qdma *qdma;
+ struct airoha_qdma *qdma = &eth->qdma[0];
+ u32 intr[ARRAY_SIZE(qdma->irqmask)];
int i;
- qdma = &eth->qdma[0];
- for (i = 0; i < ARRAY_SIZE(eth->irqmask); i++) {
+ for (i = 0; i < ARRAY_SIZE(qdma->irqmask); i++) {
intr[i] = airoha_qdma_rr(qdma, REG_INT_STATUS(i));
- intr[i] &= eth->irqmask[i];
+ intr[i] &= qdma->irqmask[i];
airoha_qdma_wr(qdma, REG_INT_STATUS(i), intr[i]);
}
@@ -1995,7 +1993,7 @@ static irqreturn_t airoha_irq_handler(in
return IRQ_NONE;
if (intr[1] & RX_DONE_INT_MASK) {
- airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX1,
+ airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX1,
RX_DONE_INT_MASK);
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
@@ -2015,7 +2013,7 @@ static irqreturn_t airoha_irq_handler(in
if (!(intr[0] & TX_DONE_INT_MASK(i)))
continue;
- airoha_qdma_irq_disable(eth, QDMA_INT_REG_IDX0,
+ airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX0,
TX_DONE_INT_MASK(i));
status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(i));
@@ -2030,12 +2028,18 @@ static irqreturn_t airoha_irq_handler(in
return IRQ_HANDLED;
}
-static int airoha_qdma_init(struct airoha_eth *eth)
+static int airoha_qdma_init(struct platform_device *pdev,
+ struct airoha_eth *eth)
{
struct airoha_qdma *qdma = &eth->qdma[0];
int err;
- err = devm_request_irq(eth->dev, eth->irq, airoha_irq_handler,
+ spin_lock_init(&qdma->irq_lock);
+ qdma->irq = platform_get_irq(pdev, 0);
+ if (qdma->irq < 0)
+ return qdma->irq;
+
+ err = devm_request_irq(eth->dev, qdma->irq, airoha_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, eth);
if (err)
return err;
@@ -2061,7 +2065,8 @@ static int airoha_qdma_init(struct airoh
return 0;
}
-static int airoha_hw_init(struct airoha_eth *eth)
+static int airoha_hw_init(struct platform_device *pdev,
+ struct airoha_eth *eth)
{
int err;
@@ -2077,7 +2082,7 @@ static int airoha_hw_init(struct airoha_
if (err)
return err;
- return airoha_qdma_init(eth);
+ return airoha_qdma_init(pdev, eth);
}
static void airoha_hw_cleanup(struct airoha_eth *eth)
@@ -2674,11 +2679,6 @@ static int airoha_probe(struct platform_
return err;
}
- spin_lock_init(&eth->irq_lock);
- eth->irq = platform_get_irq(pdev, 0);
- if (eth->irq < 0)
- return eth->irq;
-
eth->napi_dev = alloc_netdev_dummy(0);
if (!eth->napi_dev)
return -ENOMEM;
@@ -2688,7 +2688,7 @@ static int airoha_probe(struct platform_
strscpy(eth->napi_dev->name, "qdma_eth", sizeof(eth->napi_dev->name));
platform_set_drvdata(pdev, eth);
- err = airoha_hw_init(eth);
+ err = airoha_hw_init(pdev, eth);
if (err)
goto error;

View File

@ -0,0 +1,306 @@
From 9a2500ab22f059e596942172a8e4a60ae8243ce4 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:06 +0200
Subject: [PATCH 4/8] net: airoha: Add airoha_qdma pointer in
airoha_tx_irq_queue/airoha_queue structures
Move airoha_eth pointer in airoha_qdma structure from
airoha_tx_irq_queue/airoha_queue ones. This is a preliminary patch to
introduce support for multi-QDMA controllers available on EN7581.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/074565b82fd0ceefe66e186f21133d825dbd48eb.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 84 +++++++++++-----------
1 file changed, 41 insertions(+), 43 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -728,7 +728,7 @@ struct airoha_queue_entry {
};
struct airoha_queue {
- struct airoha_eth *eth;
+ struct airoha_qdma *qdma;
/* protect concurrent queue accesses */
spinlock_t lock;
@@ -747,7 +747,7 @@ struct airoha_queue {
};
struct airoha_tx_irq_queue {
- struct airoha_eth *eth;
+ struct airoha_qdma *qdma;
struct napi_struct napi;
u32 *q;
@@ -784,6 +784,7 @@ struct airoha_hw_stats {
};
struct airoha_qdma {
+ struct airoha_eth *eth;
void __iomem *regs;
/* protect concurrent irqmask accesses */
@@ -1388,8 +1389,8 @@ static int airoha_fe_init(struct airoha_
static int airoha_qdma_fill_rx_queue(struct airoha_queue *q)
{
enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
- struct airoha_qdma *qdma = &q->eth->qdma[0];
- struct airoha_eth *eth = q->eth;
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
int qid = q - &qdma->q_rx[0];
int nframes = 0;
@@ -1457,8 +1458,8 @@ static int airoha_qdma_get_gdm_port(stru
static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
{
enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
- struct airoha_qdma *qdma = &q->eth->qdma[0];
- struct airoha_eth *eth = q->eth;
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
int qid = q - &qdma->q_rx[0];
int done = 0;
@@ -1521,7 +1522,6 @@ static int airoha_qdma_rx_process(struct
static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_queue *q = container_of(napi, struct airoha_queue, napi);
- struct airoha_qdma *qdma = &q->eth->qdma[0];
int cur, done = 0;
do {
@@ -1530,14 +1530,13 @@ static int airoha_qdma_rx_napi_poll(stru
} while (cur && done < budget);
if (done < budget && napi_complete(napi))
- airoha_qdma_irq_enable(qdma, QDMA_INT_REG_IDX1,
+ airoha_qdma_irq_enable(q->qdma, QDMA_INT_REG_IDX1,
RX_DONE_INT_MASK);
return done;
}
-static int airoha_qdma_init_rx_queue(struct airoha_eth *eth,
- struct airoha_queue *q,
+static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
struct airoha_qdma *qdma, int ndesc)
{
const struct page_pool_params pp_params = {
@@ -1548,15 +1547,16 @@ static int airoha_qdma_init_rx_queue(str
.dma_dir = DMA_FROM_DEVICE,
.max_len = PAGE_SIZE,
.nid = NUMA_NO_NODE,
- .dev = eth->dev,
+ .dev = qdma->eth->dev,
.napi = &q->napi,
};
+ struct airoha_eth *eth = qdma->eth;
int qid = q - &qdma->q_rx[0], thr;
dma_addr_t dma_addr;
q->buf_size = PAGE_SIZE / 2;
q->ndesc = ndesc;
- q->eth = eth;
+ q->qdma = qdma;
q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
GFP_KERNEL);
@@ -1596,7 +1596,7 @@ static int airoha_qdma_init_rx_queue(str
static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
{
- struct airoha_eth *eth = q->eth;
+ struct airoha_eth *eth = q->qdma->eth;
while (q->queued) {
struct airoha_queue_entry *e = &q->entry[q->tail];
@@ -1610,8 +1610,7 @@ static void airoha_qdma_cleanup_rx_queue
}
}
-static int airoha_qdma_init_rx(struct airoha_eth *eth,
- struct airoha_qdma *qdma)
+static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
{
int i;
@@ -1623,8 +1622,8 @@ static int airoha_qdma_init_rx(struct ai
continue;
}
- err = airoha_qdma_init_rx_queue(eth, &qdma->q_rx[i],
- qdma, RX_DSCP_NUM(i));
+ err = airoha_qdma_init_rx_queue(&qdma->q_rx[i], qdma,
+ RX_DSCP_NUM(i));
if (err)
return err;
}
@@ -1640,9 +1639,9 @@ static int airoha_qdma_tx_napi_poll(stru
int id, done = 0;
irq_q = container_of(napi, struct airoha_tx_irq_queue, napi);
- eth = irq_q->eth;
- qdma = &eth->qdma[0];
+ qdma = irq_q->qdma;
id = irq_q - &qdma->q_tx_irq[0];
+ eth = qdma->eth;
while (irq_q->queued > 0 && done < budget) {
u32 qid, last, val = irq_q->q[irq_q->head];
@@ -1724,16 +1723,16 @@ static int airoha_qdma_tx_napi_poll(stru
return done;
}
-static int airoha_qdma_init_tx_queue(struct airoha_eth *eth,
- struct airoha_queue *q,
+static int airoha_qdma_init_tx_queue(struct airoha_queue *q,
struct airoha_qdma *qdma, int size)
{
+ struct airoha_eth *eth = qdma->eth;
int i, qid = q - &qdma->q_tx[0];
dma_addr_t dma_addr;
spin_lock_init(&q->lock);
q->ndesc = size;
- q->eth = eth;
+ q->qdma = qdma;
q->free_thr = 1 + MAX_SKB_FRAGS;
q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
@@ -1762,11 +1761,11 @@ static int airoha_qdma_init_tx_queue(str
return 0;
}
-static int airoha_qdma_tx_irq_init(struct airoha_eth *eth,
- struct airoha_tx_irq_queue *irq_q,
+static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
struct airoha_qdma *qdma, int size)
{
int id = irq_q - &qdma->q_tx_irq[0];
+ struct airoha_eth *eth = qdma->eth;
dma_addr_t dma_addr;
netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
@@ -1778,7 +1777,7 @@ static int airoha_qdma_tx_irq_init(struc
memset(irq_q->q, 0xff, size * sizeof(u32));
irq_q->size = size;
- irq_q->eth = eth;
+ irq_q->qdma = qdma;
airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr);
airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
@@ -1789,21 +1788,20 @@ static int airoha_qdma_tx_irq_init(struc
return 0;
}
-static int airoha_qdma_init_tx(struct airoha_eth *eth,
- struct airoha_qdma *qdma)
+static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
{
int i, err;
for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
- err = airoha_qdma_tx_irq_init(eth, &qdma->q_tx_irq[i],
- qdma, IRQ_QUEUE_LEN(i));
+ err = airoha_qdma_tx_irq_init(&qdma->q_tx_irq[i], qdma,
+ IRQ_QUEUE_LEN(i));
if (err)
return err;
}
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
- err = airoha_qdma_init_tx_queue(eth, &qdma->q_tx[i],
- qdma, TX_DSCP_NUM);
+ err = airoha_qdma_init_tx_queue(&qdma->q_tx[i], qdma,
+ TX_DSCP_NUM);
if (err)
return err;
}
@@ -1813,7 +1811,7 @@ static int airoha_qdma_init_tx(struct ai
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
- struct airoha_eth *eth = q->eth;
+ struct airoha_eth *eth = q->qdma->eth;
spin_lock_bh(&q->lock);
while (q->queued) {
@@ -1830,9 +1828,9 @@ static void airoha_qdma_cleanup_tx_queue
spin_unlock_bh(&q->lock);
}
-static int airoha_qdma_init_hfwd_queues(struct airoha_eth *eth,
- struct airoha_qdma *qdma)
+static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
{
+ struct airoha_eth *eth = qdma->eth;
dma_addr_t dma_addr;
u32 status;
int size;
@@ -1870,8 +1868,7 @@ static int airoha_qdma_init_hfwd_queues(
REG_LMGR_INIT_CFG);
}
-static void airoha_qdma_init_qos(struct airoha_eth *eth,
- struct airoha_qdma *qdma)
+static void airoha_qdma_init_qos(struct airoha_qdma *qdma)
{
airoha_qdma_clear(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_SCALE_MASK);
airoha_qdma_set(qdma, REG_TXWRR_MODE_CFG, TWRR_WEIGHT_BASE_MASK);
@@ -1921,8 +1918,7 @@ static void airoha_qdma_init_qos(struct
FIELD_PREP(SLA_SLOW_TICK_RATIO_MASK, 40));
}
-static int airoha_qdma_hw_init(struct airoha_eth *eth,
- struct airoha_qdma *qdma)
+static int airoha_qdma_hw_init(struct airoha_qdma *qdma)
{
int i;
@@ -1959,7 +1955,7 @@ static int airoha_qdma_hw_init(struct ai
GLOBAL_CFG_TX_WB_DONE_MASK |
FIELD_PREP(GLOBAL_CFG_MAX_ISSUE_NUM_MASK, 2));
- airoha_qdma_init_qos(eth, qdma);
+ airoha_qdma_init_qos(qdma);
/* disable qdma rx delay interrupt */
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
@@ -2035,6 +2031,8 @@ static int airoha_qdma_init(struct platf
int err;
spin_lock_init(&qdma->irq_lock);
+ qdma->eth = eth;
+
qdma->irq = platform_get_irq(pdev, 0);
if (qdma->irq < 0)
return qdma->irq;
@@ -2044,19 +2042,19 @@ static int airoha_qdma_init(struct platf
if (err)
return err;
- err = airoha_qdma_init_rx(eth, qdma);
+ err = airoha_qdma_init_rx(qdma);
if (err)
return err;
- err = airoha_qdma_init_tx(eth, qdma);
+ err = airoha_qdma_init_tx(qdma);
if (err)
return err;
- err = airoha_qdma_init_hfwd_queues(eth, qdma);
+ err = airoha_qdma_init_hfwd_queues(qdma);
if (err)
return err;
- err = airoha_qdma_hw_init(eth, qdma);
+ err = airoha_qdma_hw_init(qdma);
if (err)
return err;

View File

@ -0,0 +1,45 @@
From e3d6bfdfc0aeb8c1d7965413b1050ec07f9761e5 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:07 +0200
Subject: [PATCH 5/8] net: airoha: Use qdma pointer as private structure in
airoha_irq_handler routine
This is a preliminary patch to support multi-QDMA controllers.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/1e40c3cb973881c0eb3c3c247c78550da62054ab.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -1974,8 +1974,7 @@ static int airoha_qdma_hw_init(struct ai
static irqreturn_t airoha_irq_handler(int irq, void *dev_instance)
{
- struct airoha_eth *eth = dev_instance;
- struct airoha_qdma *qdma = &eth->qdma[0];
+ struct airoha_qdma *qdma = dev_instance;
u32 intr[ARRAY_SIZE(qdma->irqmask)];
int i;
@@ -1985,7 +1984,7 @@ static irqreturn_t airoha_irq_handler(in
airoha_qdma_wr(qdma, REG_INT_STATUS(i), intr[i]);
}
- if (!test_bit(DEV_STATE_INITIALIZED, &eth->state))
+ if (!test_bit(DEV_STATE_INITIALIZED, &qdma->eth->state))
return IRQ_NONE;
if (intr[1] & RX_DONE_INT_MASK) {
@@ -2038,7 +2037,7 @@ static int airoha_qdma_init(struct platf
return qdma->irq;
err = devm_request_irq(eth->dev, qdma->irq, airoha_irq_handler,
- IRQF_SHARED, KBUILD_MODNAME, eth);
+ IRQF_SHARED, KBUILD_MODNAME, qdma);
if (err)
return err;

View File

@ -0,0 +1,131 @@
From e618447cf492d04415007336eec025fae6e9a2ea Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:08 +0200
Subject: [PATCH 6/8] net: airoha: Allow mapping IO region for multiple qdma
controllers
Map MMIO regions of both qdma controllers available on EN7581 SoC.
Run airoha_hw_cleanup routine for both QDMA controllers available on
EN7581 SoC removing airoha_eth module or in airoha_probe error path.
This is a preliminary patch to support multi-QDMA controllers.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/a734ae608da14b67ae749b375d880dbbc70868ea.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 56 ++++++++++++----------
1 file changed, 32 insertions(+), 24 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -2024,15 +2024,25 @@ static irqreturn_t airoha_irq_handler(in
}
static int airoha_qdma_init(struct platform_device *pdev,
- struct airoha_eth *eth)
+ struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
{
- struct airoha_qdma *qdma = &eth->qdma[0];
- int err;
+ int err, id = qdma - &eth->qdma[0];
+ const char *res;
spin_lock_init(&qdma->irq_lock);
qdma->eth = eth;
- qdma->irq = platform_get_irq(pdev, 0);
+ res = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d", id);
+ if (!res)
+ return -ENOMEM;
+
+ qdma->regs = devm_platform_ioremap_resource_byname(pdev, res);
+ if (IS_ERR(qdma->regs))
+ return dev_err_probe(eth->dev, PTR_ERR(qdma->regs),
+ "failed to iomap qdma%d regs\n", id);
+
+ qdma->irq = platform_get_irq(pdev, 4 * id);
if (qdma->irq < 0)
return qdma->irq;
@@ -2053,19 +2063,13 @@ static int airoha_qdma_init(struct platf
if (err)
return err;
- err = airoha_qdma_hw_init(qdma);
- if (err)
- return err;
-
- set_bit(DEV_STATE_INITIALIZED, &eth->state);
-
- return 0;
+ return airoha_qdma_hw_init(qdma);
}
static int airoha_hw_init(struct platform_device *pdev,
struct airoha_eth *eth)
{
- int err;
+ int err, i;
/* disable xsi */
reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), eth->xsi_rsts);
@@ -2079,12 +2083,19 @@ static int airoha_hw_init(struct platfor
if (err)
return err;
- return airoha_qdma_init(pdev, eth);
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ err = airoha_qdma_init(pdev, eth, &eth->qdma[i]);
+ if (err)
+ return err;
+ }
+
+ set_bit(DEV_STATE_INITIALIZED, &eth->state);
+
+ return 0;
}
-static void airoha_hw_cleanup(struct airoha_eth *eth)
+static void airoha_hw_cleanup(struct airoha_qdma *qdma)
{
- struct airoha_qdma *qdma = &eth->qdma[0];
int i;
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
@@ -2645,13 +2656,6 @@ static int airoha_probe(struct platform_
return dev_err_probe(eth->dev, PTR_ERR(eth->fe_regs),
"failed to iomap fe regs\n");
- eth->qdma[0].regs = devm_platform_ioremap_resource_byname(pdev,
- "qdma0");
- if (IS_ERR(eth->qdma[0].regs))
- return dev_err_probe(eth->dev,
- PTR_ERR(eth->qdma[0].regs),
- "failed to iomap qdma regs\n");
-
eth->rsts[0].id = "fe";
eth->rsts[1].id = "pdma";
eth->rsts[2].id = "qdma";
@@ -2707,7 +2711,9 @@ static int airoha_probe(struct platform_
return 0;
error:
- airoha_hw_cleanup(eth);
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_hw_cleanup(&eth->qdma[i]);
+
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -2725,7 +2731,9 @@ static void airoha_remove(struct platfor
struct airoha_eth *eth = platform_get_drvdata(pdev);
int i;
- airoha_hw_cleanup(eth);
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_hw_cleanup(&eth->qdma[i]);
+
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];

View File

@ -0,0 +1,38 @@
From 160231e34b8e9512ba20530f3e68fb0ac499af87 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:09 +0200
Subject: [PATCH 7/8] net: airoha: Start all qdma NAPIs in airoha_probe()
This is a preliminary patch to support multi-QDMA controllers.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/b51cf69c94d8cbc81e0a0b35587f024d01e6d9c0.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -2122,9 +2122,8 @@ static void airoha_hw_cleanup(struct air
}
}
-static void airoha_qdma_start_napi(struct airoha_eth *eth)
+static void airoha_qdma_start_napi(struct airoha_qdma *qdma)
{
- struct airoha_qdma *qdma = &eth->qdma[0];
int i;
for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
@@ -2693,7 +2692,9 @@ static int airoha_probe(struct platform_
if (err)
goto error;
- airoha_qdma_start_napi(eth);
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_start_napi(&eth->qdma[i]);
+
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_device_is_compatible(np, "airoha,eth-mac"))
continue;

View File

@ -0,0 +1,174 @@
From 9304640f2f78147dddf97a5ea01502ae175e41d9 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 16:35:10 +0200
Subject: [PATCH 8/8] net: airoha: Link the gdm port to the selected qdma
controller
Link the running gdm port to the qdma controller used to connect with
the CPU. Moreover, load all QDMA controllers available on EN7581 SoC.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/95b515df34ba4727f7ae5b14a1d0462cceec84ff.1722522582.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 37 +++++++++++-----------
1 file changed, 19 insertions(+), 18 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -18,7 +18,7 @@
#include <uapi/linux/ppp_defs.h>
#define AIROHA_MAX_NUM_GDM_PORTS 1
-#define AIROHA_MAX_NUM_QDMA 1
+#define AIROHA_MAX_NUM_QDMA 2
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_NUM_XSI_RSTS 5
#define AIROHA_MAX_MTU 2000
@@ -805,8 +805,8 @@ struct airoha_qdma {
};
struct airoha_gdm_port {
+ struct airoha_qdma *qdma;
struct net_device *dev;
- struct airoha_eth *eth;
int id;
struct airoha_hw_stats stats;
@@ -2139,7 +2139,7 @@ static void airoha_qdma_start_napi(struc
static void airoha_update_hw_stats(struct airoha_gdm_port *port)
{
- struct airoha_eth *eth = port->eth;
+ struct airoha_eth *eth = port->qdma->eth;
u32 val, i = 0;
spin_lock(&port->stats.lock);
@@ -2284,22 +2284,22 @@ static void airoha_update_hw_stats(struc
static int airoha_dev_open(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
- struct airoha_eth *eth = port->eth;
+ struct airoha_qdma *qdma = port->qdma;
int err;
netif_tx_start_all_queues(dev);
- err = airoha_set_gdm_ports(eth, true);
+ err = airoha_set_gdm_ports(qdma->eth, true);
if (err)
return err;
if (netdev_uses_dsa(dev))
- airoha_fe_set(eth, REG_GDM_INGRESS_CFG(port->id),
+ airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
else
- airoha_fe_clear(eth, REG_GDM_INGRESS_CFG(port->id),
+ airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
- airoha_qdma_set(&eth->qdma[0], REG_QDMA_GLOBAL_CFG,
+ airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
GLOBAL_CFG_RX_DMA_EN_MASK);
@@ -2309,15 +2309,15 @@ static int airoha_dev_open(struct net_de
static int airoha_dev_stop(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
- struct airoha_eth *eth = port->eth;
+ struct airoha_qdma *qdma = port->qdma;
int err;
netif_tx_disable(dev);
- err = airoha_set_gdm_ports(eth, false);
+ err = airoha_set_gdm_ports(qdma->eth, false);
if (err)
return err;
- airoha_qdma_clear(&eth->qdma[0], REG_QDMA_GLOBAL_CFG,
+ airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
GLOBAL_CFG_RX_DMA_EN_MASK);
@@ -2333,7 +2333,7 @@ static int airoha_dev_set_macaddr(struct
if (err)
return err;
- airoha_set_macaddr(port->eth, dev->dev_addr);
+ airoha_set_macaddr(port->qdma->eth, dev->dev_addr);
return 0;
}
@@ -2342,7 +2342,7 @@ static int airoha_dev_init(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
- airoha_set_macaddr(port->eth, dev->dev_addr);
+ airoha_set_macaddr(port->qdma->eth, dev->dev_addr);
return 0;
}
@@ -2376,10 +2376,9 @@ static netdev_tx_t airoha_dev_xmit(struc
struct airoha_gdm_port *port = netdev_priv(dev);
u32 msg0 = 0, msg1, len = skb_headlen(skb);
int i, qid = skb_get_queue_mapping(skb);
- struct airoha_eth *eth = port->eth;
+ struct airoha_qdma *qdma = port->qdma;
u32 nr_frags = 1 + sinfo->nr_frags;
struct netdev_queue *txq;
- struct airoha_qdma *qdma;
struct airoha_queue *q;
void *data = skb->data;
u16 index;
@@ -2407,7 +2406,6 @@ static netdev_tx_t airoha_dev_xmit(struc
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
- qdma = &eth->qdma[0];
q = &qdma->q_tx[qid];
if (WARN_ON_ONCE(!q->ndesc))
goto error;
@@ -2490,7 +2488,7 @@ static void airoha_ethtool_get_drvinfo(s
struct ethtool_drvinfo *info)
{
struct airoha_gdm_port *port = netdev_priv(dev);
- struct airoha_eth *eth = port->eth;
+ struct airoha_eth *eth = port->qdma->eth;
strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver));
strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info));
@@ -2571,6 +2569,7 @@ static int airoha_alloc_gdm_port(struct
{
const __be32 *id_ptr = of_get_property(np, "reg", NULL);
struct airoha_gdm_port *port;
+ struct airoha_qdma *qdma;
struct net_device *dev;
int err, index;
u32 id;
@@ -2600,6 +2599,7 @@ static int airoha_alloc_gdm_port(struct
return -ENOMEM;
}
+ qdma = &eth->qdma[index % AIROHA_MAX_NUM_QDMA];
dev->netdev_ops = &airoha_netdev_ops;
dev->ethtool_ops = &airoha_ethtool_ops;
dev->max_mtu = AIROHA_MAX_MTU;
@@ -2609,6 +2609,7 @@ static int airoha_alloc_gdm_port(struct
NETIF_F_SG | NETIF_F_TSO;
dev->features |= dev->hw_features;
dev->dev.of_node = np;
+ dev->irq = qdma->irq;
SET_NETDEV_DEV(dev, eth->dev);
err = of_get_ethdev_address(np, dev);
@@ -2624,8 +2625,8 @@ static int airoha_alloc_gdm_port(struct
port = netdev_priv(dev);
u64_stats_init(&port->stats.syncp);
spin_lock_init(&port->stats.lock);
+ port->qdma = qdma;
port->dev = dev;
- port->eth = eth;
port->id = id;
eth->ports[index] = port;

View File

@ -0,0 +1,44 @@
From 63a796b4988c3dca83176a534890b510d44f105a Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 3 Aug 2024 17:50:50 +0200
Subject: [PATCH] net: airoha: honor reset return value in airoha_hw_init()
Take into account return value from reset_control_bulk_assert and
reset_control_bulk_deassert routines in airoha_hw_init().
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/f49dc04a87653e0155f4fab3e3eb584785c8ad6a.1722699555.git.lorenzo@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -2072,13 +2072,21 @@ static int airoha_hw_init(struct platfor
int err, i;
/* disable xsi */
- reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), eth->xsi_rsts);
+ err = reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts),
+ eth->xsi_rsts);
+ if (err)
+ return err;
+
+ err = reset_control_bulk_assert(ARRAY_SIZE(eth->rsts), eth->rsts);
+ if (err)
+ return err;
- reset_control_bulk_assert(ARRAY_SIZE(eth->rsts), eth->rsts);
- msleep(20);
- reset_control_bulk_deassert(ARRAY_SIZE(eth->rsts), eth->rsts);
msleep(20);
+ err = reset_control_bulk_deassert(ARRAY_SIZE(eth->rsts), eth->rsts);
+ if (err)
+ return err;
+ msleep(20);
err = airoha_fe_init(eth);
if (err)
return err;

View File

@ -0,0 +1,85 @@
From 812a2751e827fa1eb01f3bd268b4d74c23f4226a Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 21 Aug 2024 09:30:14 +0200
Subject: [PATCH] net: airoha: configure hw mac address according to the port
id
GDM1 port on EN7581 SoC is connected to the lan dsa switch.
GDM{2,3,4} can be used as wan port connected to an external
phy module. Configure hw mac address registers according to the port id.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240821-airoha-eth-wan-mac-addr-v2-1-8706d0cd6cd5@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 32 ++++++++++++++++------
1 file changed, 23 insertions(+), 9 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -67,9 +67,11 @@
#define FE_RST_GDM3_MBI_ARB_MASK BIT(2)
#define FE_RST_CORE_MASK BIT(0)
+#define REG_FE_WAN_MAC_H 0x0030
#define REG_FE_LAN_MAC_H 0x0040
-#define REG_FE_LAN_MAC_LMIN 0x0044
-#define REG_FE_LAN_MAC_LMAX 0x0048
+
+#define REG_FE_MAC_LMIN(_n) ((_n) + 0x04)
+#define REG_FE_MAC_LMAX(_n) ((_n) + 0x08)
#define REG_FE_CDM1_OQ_MAP0 0x0050
#define REG_FE_CDM1_OQ_MAP1 0x0054
@@ -900,16 +902,28 @@ static void airoha_qdma_irq_disable(stru
airoha_qdma_set_irqmask(qdma, index, mask, 0);
}
-static void airoha_set_macaddr(struct airoha_eth *eth, const u8 *addr)
+static bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port)
{
- u32 val;
+ /* GDM1 port on EN7581 SoC is connected to the lan dsa switch.
+ * GDM{2,3,4} can be used as wan port connected to an external
+ * phy module.
+ */
+ return port->id == 1;
+}
+
+static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
+{
+ struct airoha_eth *eth = port->qdma->eth;
+ u32 val, reg;
+ reg = airhoa_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H
+ : REG_FE_WAN_MAC_H;
val = (addr[0] << 16) | (addr[1] << 8) | addr[2];
- airoha_fe_wr(eth, REG_FE_LAN_MAC_H, val);
+ airoha_fe_wr(eth, reg, val);
val = (addr[3] << 16) | (addr[4] << 8) | addr[5];
- airoha_fe_wr(eth, REG_FE_LAN_MAC_LMIN, val);
- airoha_fe_wr(eth, REG_FE_LAN_MAC_LMAX, val);
+ airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val);
+ airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val);
}
static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr,
@@ -2341,7 +2355,7 @@ static int airoha_dev_set_macaddr(struct
if (err)
return err;
- airoha_set_macaddr(port->qdma->eth, dev->dev_addr);
+ airoha_set_macaddr(port, dev->dev_addr);
return 0;
}
@@ -2350,7 +2364,7 @@ static int airoha_dev_init(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
- airoha_set_macaddr(port->qdma->eth, dev->dev_addr);
+ airoha_set_macaddr(port, dev->dev_addr);
return 0;
}

View File

@ -0,0 +1,26 @@
From 7d2bd8ac9d2494cf9b16c4b00df9424ad24ed18c Mon Sep 17 00:00:00 2001
From: Liao Chen <liaochen4@huawei.com>
Date: Mon, 26 Aug 2024 09:18:58 +0000
Subject: [PATCH] net: airoha: fix module autoloading
Add MODULE_DEVICE_TABLE(), so modules could be properly autoloaded
based on the alias from of_device_id table.
Signed-off-by: Liao Chen <liaochen4@huawei.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240826091858.369910-4-liaochen4@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -2776,6 +2776,7 @@ static const struct of_device_id of_airo
{ .compatible = "airoha,en7581-eth" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, of_airoha_match);
static struct platform_driver airoha_driver = {
.probe = airoha_probe,

View File

@ -0,0 +1,40 @@
From 8e38e08f2c560328a873c35aff1a0dbea6a7d084 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 1 Oct 2024 12:10:25 +0200
Subject: [PATCH 2/2] net: airoha: fix PSE memory configuration in
airoha_fe_pse_ports_init()
Align PSE memory configuration to vendor SDK. In particular, increase
initial value of PSE reserved memory in airoha_fe_pse_ports_init()
routine by the value used for the second Packet Processor Engine (PPE2)
and do not overwrite the default value.
Introduced by commit 23020f049327 ("net: airoha: Introduce ethernet support
for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241001-airoha-eth-pse-fix-v2-2-9a56cdffd074@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -1166,11 +1166,13 @@ static void airoha_fe_pse_ports_init(str
[FE_PSE_PORT_GDM4] = 2,
[FE_PSE_PORT_CDM5] = 2,
};
+ u32 all_rsv;
int q;
+ all_rsv = airoha_fe_get_pse_all_rsv(eth);
/* hw misses PPE2 oq rsv */
- airoha_fe_set(eth, REG_FE_PSE_BUF_SET,
- PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2]);
+ all_rsv += PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2];
+ airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv);
/* CMD1 */
for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++)

View File

@ -0,0 +1,52 @@
From 1f3e7ff4f296af1f4350f457d5bd82bc825e645a Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 1 Oct 2024 12:10:24 +0200
Subject: [PATCH 1/2] net: airoha: read default PSE reserved pages value before
updating
Store the default value for the number of PSE reserved pages in orig_val
at the beginning of airoha_fe_set_pse_oq_rsv routine, before updating it
with airoha_fe_set_pse_queue_rsv_pages().
Introduce airoha_fe_get_pse_all_rsv utility routine.
Introduced by commit 23020f049327 ("net: airoha: Introduce ethernet support
for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241001-airoha-eth-pse-fix-v2-1-9a56cdffd074@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -1116,17 +1116,23 @@ static void airoha_fe_set_pse_queue_rsv_
PSE_CFG_WR_EN_MASK | PSE_CFG_OQRSV_SEL_MASK);
}
+static u32 airoha_fe_get_pse_all_rsv(struct airoha_eth *eth)
+{
+ u32 val = airoha_fe_rr(eth, REG_FE_PSE_BUF_SET);
+
+ return FIELD_GET(PSE_ALLRSV_MASK, val);
+}
+
static int airoha_fe_set_pse_oq_rsv(struct airoha_eth *eth,
u32 port, u32 queue, u32 val)
{
- u32 orig_val, tmp, all_rsv, fq_limit;
+ u32 orig_val = airoha_fe_get_pse_queue_rsv_pages(eth, port, queue);
+ u32 tmp, all_rsv, fq_limit;
airoha_fe_set_pse_queue_rsv_pages(eth, port, queue, val);
/* modify all rsv */
- orig_val = airoha_fe_get_pse_queue_rsv_pages(eth, port, queue);
- tmp = airoha_fe_rr(eth, REG_FE_PSE_BUF_SET);
- all_rsv = FIELD_GET(PSE_ALLRSV_MASK, tmp);
+ all_rsv = airoha_fe_get_pse_all_rsv(eth);
all_rsv += (val - orig_val);
airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK,
FIELD_PREP(PSE_ALLRSV_MASK, all_rsv));

View File

@ -0,0 +1,45 @@
From 3dc6e998d18bfba6e0dc979d3cc68eba98dfeef7 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Fri, 4 Oct 2024 15:51:26 +0200
Subject: [PATCH] net: airoha: Update tx cpu dma ring idx at the end of xmit
loop
Move the tx cpu dma ring index update out of transmit loop of
airoha_dev_xmit routine in order to not start transmitting the packet
before it is fully DMA mapped (e.g. fragmented skbs).
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Reported-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241004-airoha-eth-7581-mapping-fix-v1-1-8e4279ab1812@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -2480,10 +2480,6 @@ static netdev_tx_t airoha_dev_xmit(struc
e->dma_addr = addr;
e->dma_len = len;
- airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
- TX_RING_CPU_IDX_MASK,
- FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
-
data = skb_frag_address(frag);
len = skb_frag_size(frag);
}
@@ -2492,6 +2488,11 @@ static netdev_tx_t airoha_dev_xmit(struc
q->queued += i;
skb_tx_timestamp(skb);
+ if (!netdev_xmit_more())
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
+ TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
+
if (q->ndesc - q->queued < q->free_thr)
netif_tx_stop_queue(txq);

View File

@ -0,0 +1,33 @@
From 2518b119639162251b6cc7195aec394930c1d867 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 9 Oct 2024 00:21:47 +0200
Subject: [PATCH] net: airoha: Fix EGRESS_RATE_METER_EN_MASK definition
Fix typo in EGRESS_RATE_METER_EN_MASK mask definition. This bus in not
introducing any user visible problem since, even if we are setting
EGRESS_RATE_METER_EN_MASK bit in REG_EGRESS_RATE_METER_CFG register,
egress QoS metering is not supported yet since we are missing some other
hw configurations (e.g token bucket rate, token bucket size).
Introduced by commit 23020f049327 ("net: airoha: Introduce ethernet support
for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241009-airoha-fixes-v2-1-18af63ec19bf@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -554,7 +554,7 @@
#define FWD_DSCP_LOW_THR_MASK GENMASK(17, 0)
#define REG_EGRESS_RATE_METER_CFG 0x100c
-#define EGRESS_RATE_METER_EN_MASK BIT(29)
+#define EGRESS_RATE_METER_EN_MASK BIT(31)
#define EGRESS_RATE_METER_EQ_RATE_EN_MASK BIT(17)
#define EGRESS_RATE_METER_WINDOW_SZ_MASK GENMASK(16, 12)
#define EGRESS_RATE_METER_TIMESLICE_MASK GENMASK(10, 0)

View File

@ -0,0 +1,42 @@
From 1d304174106c93ce05f6088813ad7203b3eb381a Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 12 Oct 2024 11:01:11 +0200
Subject: [PATCH] net: airoha: Implement BQL support
Introduce BQL support in the airoha_eth driver reporting to the kernel
info about tx hw DMA queues in order to avoid bufferbloat and keep the
latency small.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20241012-en7581-bql-v2-1-4deb4efdb60b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/mediatek/airoha_eth.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -1710,9 +1710,11 @@ static int airoha_qdma_tx_napi_poll(stru
WRITE_ONCE(desc->msg1, 0);
if (skb) {
+ u16 queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq;
- txq = netdev_get_tx_queue(skb->dev, qid);
+ txq = netdev_get_tx_queue(skb->dev, queue);
+ netdev_tx_completed_queue(txq, 1, skb->len);
if (netif_tx_queue_stopped(txq) &&
q->ndesc - q->queued >= q->free_thr)
netif_tx_wake_queue(txq);
@@ -2488,7 +2490,9 @@ static netdev_tx_t airoha_dev_xmit(struc
q->queued += i;
skb_tx_timestamp(skb);
- if (!netdev_xmit_more())
+ netdev_tx_sent_queue(txq, skb->len);
+
+ if (netif_xmit_stopped(txq) || !netdev_xmit_more())
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));

View File

@ -0,0 +1,98 @@
From 457e74667f452d7f071ad2b2d9313ec62ebc4b02 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 6 Apr 2024 12:43:43 +0200
Subject: [PATCH 1/2] clk: en7523: Add en_clk_soc_data data structure
Introduce en_clk_soc_data data structure in order to define multiple
clk_ops for each supported SoC. This is a preliminary patch to
introduce EN7581 clock support.
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/562a0da8d7874a02a324687c152c87a1549924bd.1712399981.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-en7523.c | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -3,8 +3,8 @@
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
-#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <dt-bindings/clock/en7523-clk.h>
#define REG_PCI_CONTROL 0x88
@@ -48,6 +48,10 @@ struct en_clk_gate {
struct clk_hw hw;
};
+struct en_clk_soc_data {
+ const struct clk_ops pcie_ops;
+};
+
static const u32 gsw_base[] = { 400000000, 500000000 };
static const u32 emi_base[] = { 333000000, 400000000 };
static const u32 bus_base[] = { 500000000, 540000000 };
@@ -150,11 +154,6 @@ static const struct en_clk_desc en7523_b
}
};
-static const struct of_device_id of_match_clk_en7523[] = {
- { .compatible = "airoha,en7523-scu", },
- { /* sentinel */ }
-};
-
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
@@ -252,14 +251,10 @@ static void en7523_pci_unprepare(struct
static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
void __iomem *np_base)
{
- static const struct clk_ops pcie_gate_ops = {
- .is_enabled = en7523_pci_is_enabled,
- .prepare = en7523_pci_prepare,
- .unprepare = en7523_pci_unprepare,
- };
+ const struct en_clk_soc_data *soc_data = device_get_match_data(dev);
struct clk_init_data init = {
.name = "pcie",
- .ops = &pcie_gate_ops,
+ .ops = &soc_data->pcie_ops,
};
struct en_clk_gate *cg;
@@ -269,7 +264,7 @@ static struct clk_hw *en7523_register_pc
cg->base = np_base;
cg->hw.init = &init;
- en7523_pci_unprepare(&cg->hw);
+ init.ops->unprepare(&cg->hw);
if (clk_hw_register(dev, &cg->hw))
return NULL;
@@ -338,6 +333,19 @@ static int en7523_clk_probe(struct platf
return r;
}
+static const struct en_clk_soc_data en7523_data = {
+ .pcie_ops = {
+ .is_enabled = en7523_pci_is_enabled,
+ .prepare = en7523_pci_prepare,
+ .unprepare = en7523_pci_unprepare,
+ },
+};
+
+static const struct of_device_id of_match_clk_en7523[] = {
+ { .compatible = "airoha,en7523-scu", .data = &en7523_data },
+ { /* sentinel */ }
+};
+
static struct platform_driver clk_en7523_drv = {
.probe = en7523_clk_probe,
.driver = {

View File

@ -0,0 +1,248 @@
From 66bc47326ce2a319add7e933d9340215711236ac Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 6 Apr 2024 12:43:44 +0200
Subject: [PATCH 2/2] clk: en7523: Add EN7581 support
Introduce EN7581 clock support to clk-en7523 driver.
Add hw_init callback to en_clk_soc_data data structure.
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/57b6e53ed4d2b2e38abff6a3ea56841bad6be8a9.1712399981.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-en7523.c | 157 +++++++++++++++++++++++++++++++++++++--
1 file changed, 152 insertions(+), 5 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -10,7 +10,9 @@
#define REG_PCI_CONTROL 0x88
#define REG_PCI_CONTROL_PERSTOUT BIT(29)
#define REG_PCI_CONTROL_PERSTOUT1 BIT(26)
+#define REG_PCI_CONTROL_REFCLK_EN0 BIT(23)
#define REG_PCI_CONTROL_REFCLK_EN1 BIT(22)
+#define REG_PCI_CONTROL_PERSTOUT2 BIT(16)
#define REG_GSW_CLK_DIV_SEL 0x1b4
#define REG_EMI_CLK_DIV_SEL 0x1b8
#define REG_BUS_CLK_DIV_SEL 0x1bc
@@ -18,10 +20,25 @@
#define REG_SPI_CLK_FREQ_SEL 0x1c8
#define REG_NPU_CLK_DIV_SEL 0x1fc
#define REG_CRYPTO_CLKSRC 0x200
-#define REG_RESET_CONTROL 0x834
+#define REG_RESET_CONTROL2 0x830
+#define REG_RESET2_CONTROL_PCIE2 BIT(27)
+#define REG_RESET_CONTROL1 0x834
#define REG_RESET_CONTROL_PCIEHB BIT(29)
#define REG_RESET_CONTROL_PCIE1 BIT(27)
#define REG_RESET_CONTROL_PCIE2 BIT(26)
+/* EN7581 */
+#define REG_PCIE0_MEM 0x00
+#define REG_PCIE0_MEM_MASK 0x04
+#define REG_PCIE1_MEM 0x08
+#define REG_PCIE1_MEM_MASK 0x0c
+#define REG_PCIE2_MEM 0x10
+#define REG_PCIE2_MEM_MASK 0x14
+#define REG_PCIE_RESET_OPEN_DRAIN 0x018c
+#define REG_PCIE_RESET_OPEN_DRAIN_MASK GENMASK(2, 0)
+#define REG_NP_SCU_PCIC 0x88
+#define REG_NP_SCU_SSTR 0x9c
+#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
+#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
struct en_clk_desc {
int id;
@@ -50,6 +67,8 @@ struct en_clk_gate {
struct en_clk_soc_data {
const struct clk_ops pcie_ops;
+ int (*hw_init)(struct platform_device *pdev, void __iomem *base,
+ void __iomem *np_base);
};
static const u32 gsw_base[] = { 400000000, 500000000 };
@@ -216,14 +235,14 @@ static int en7523_pci_prepare(struct clk
usleep_range(1000, 2000);
/* Reset to default */
- val = readl(np_base + REG_RESET_CONTROL);
+ val = readl(np_base + REG_RESET_CONTROL1);
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
REG_RESET_CONTROL_PCIEHB;
- writel(val & ~mask, np_base + REG_RESET_CONTROL);
+ writel(val & ~mask, np_base + REG_RESET_CONTROL1);
usleep_range(1000, 2000);
- writel(val | mask, np_base + REG_RESET_CONTROL);
+ writel(val | mask, np_base + REG_RESET_CONTROL1);
msleep(100);
- writel(val & ~mask, np_base + REG_RESET_CONTROL);
+ writel(val & ~mask, np_base + REG_RESET_CONTROL1);
usleep_range(5000, 10000);
/* Release device */
@@ -264,6 +283,9 @@ static struct clk_hw *en7523_register_pc
cg->base = np_base;
cg->hw.init = &init;
+
+ if (init.ops->disable)
+ init.ops->disable(&cg->hw);
init.ops->unprepare(&cg->hw);
if (clk_hw_register(dev, &cg->hw))
@@ -272,6 +294,111 @@ static struct clk_hw *en7523_register_pc
return &cg->hw;
}
+static int en7581_pci_is_enabled(struct clk_hw *hw)
+{
+ struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ u32 val, mask;
+
+ mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
+ val = readl(cg->base + REG_PCI_CONTROL);
+ return (val & mask) == mask;
+}
+
+static int en7581_pci_prepare(struct clk_hw *hw)
+{
+ struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ void __iomem *np_base = cg->base;
+ u32 val, mask;
+
+ mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
+ REG_RESET_CONTROL_PCIEHB;
+ val = readl(np_base + REG_RESET_CONTROL1);
+ writel(val & ~mask, np_base + REG_RESET_CONTROL1);
+ val = readl(np_base + REG_RESET_CONTROL2);
+ writel(val & ~REG_RESET2_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
+ usleep_range(5000, 10000);
+
+ return 0;
+}
+
+static int en7581_pci_enable(struct clk_hw *hw)
+{
+ struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ void __iomem *np_base = cg->base;
+ u32 val, mask;
+
+ mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
+ REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
+ REG_PCI_CONTROL_PERSTOUT;
+ val = readl(np_base + REG_PCI_CONTROL);
+ writel(val | mask, np_base + REG_PCI_CONTROL);
+ msleep(250);
+
+ return 0;
+}
+
+static void en7581_pci_unprepare(struct clk_hw *hw)
+{
+ struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ void __iomem *np_base = cg->base;
+ u32 val, mask;
+
+ mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
+ REG_RESET_CONTROL_PCIEHB;
+ val = readl(np_base + REG_RESET_CONTROL1);
+ writel(val | mask, np_base + REG_RESET_CONTROL1);
+ mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2;
+ writel(val | mask, np_base + REG_RESET_CONTROL1);
+ val = readl(np_base + REG_RESET_CONTROL2);
+ writel(val | REG_RESET_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
+ msleep(100);
+}
+
+static void en7581_pci_disable(struct clk_hw *hw)
+{
+ struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ void __iomem *np_base = cg->base;
+ u32 val, mask;
+
+ mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
+ REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
+ REG_PCI_CONTROL_PERSTOUT;
+ val = readl(np_base + REG_PCI_CONTROL);
+ writel(val & ~mask, np_base + REG_PCI_CONTROL);
+ usleep_range(1000, 2000);
+}
+
+static int en7581_clk_hw_init(struct platform_device *pdev,
+ void __iomem *base,
+ void __iomem *np_base)
+{
+ void __iomem *pb_base;
+ u32 val;
+
+ pb_base = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(pb_base))
+ return PTR_ERR(pb_base);
+
+ val = readl(np_base + REG_NP_SCU_SSTR);
+ val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
+ writel(val, np_base + REG_NP_SCU_SSTR);
+ val = readl(np_base + REG_NP_SCU_PCIC);
+ writel(val | 3, np_base + REG_NP_SCU_PCIC);
+
+ writel(0x20000000, pb_base + REG_PCIE0_MEM);
+ writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK);
+ writel(0x24000000, pb_base + REG_PCIE1_MEM);
+ writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK);
+ writel(0x28000000, pb_base + REG_PCIE2_MEM);
+ writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
+
+ val = readl(base + REG_PCIE_RESET_OPEN_DRAIN);
+ writel(val | REG_PCIE_RESET_OPEN_DRAIN_MASK,
+ base + REG_PCIE_RESET_OPEN_DRAIN);
+
+ return 0;
+}
+
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
void __iomem *base, void __iomem *np_base)
{
@@ -304,6 +431,7 @@ static void en7523_register_clocks(struc
static int en7523_clk_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
+ const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
void __iomem *base, *np_base;
int r;
@@ -316,6 +444,13 @@ static int en7523_clk_probe(struct platf
if (IS_ERR(np_base))
return PTR_ERR(np_base);
+ soc_data = device_get_match_data(&pdev->dev);
+ if (soc_data->hw_init) {
+ r = soc_data->hw_init(pdev, base, np_base);
+ if (r)
+ return r;
+ }
+
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
GFP_KERNEL);
@@ -341,8 +476,20 @@ static const struct en_clk_soc_data en75
},
};
+static const struct en_clk_soc_data en7581_data = {
+ .pcie_ops = {
+ .is_enabled = en7581_pci_is_enabled,
+ .prepare = en7581_pci_prepare,
+ .enable = en7581_pci_enable,
+ .unprepare = en7581_pci_unprepare,
+ .disable = en7581_pci_disable,
+ },
+ .hw_init = en7581_clk_hw_init,
+};
+
static const struct of_device_id of_match_clk_en7523[] = {
{ .compatible = "airoha,en7523-scu", .data = &en7523_data },
+ { .compatible = "airoha,en7581-scu", .data = &en7581_data },
{ /* sentinel */ }
};

View File

@ -0,0 +1,270 @@
From e0d8ea4ed5fa70fd085a54d0b574a044b9407c39 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 27 Jun 2024 13:04:23 +0200
Subject: [PATCH 1/4] clk: en7523: Add reset-controller support for EN7581 SoC
Introduce reset API support to EN7581 clock driver.
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/4f735d17e549ea53769bf5a3f50406debb879a44.1719485847.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-en7523.c | 192 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 187 insertions(+), 5 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -5,7 +5,11 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/reset-controller.h>
#include <dt-bindings/clock/en7523-clk.h>
+#include <dt-bindings/reset/airoha,en7581-reset.h>
+
+#define RST_NR_PER_BANK 32
#define REG_PCI_CONTROL 0x88
#define REG_PCI_CONTROL_PERSTOUT BIT(29)
@@ -40,6 +44,9 @@
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_RST_CTRL2 0x00
+#define REG_RST_CTRL1 0x04
+
struct en_clk_desc {
int id;
const char *name;
@@ -65,8 +72,20 @@ struct en_clk_gate {
struct clk_hw hw;
};
+struct en_rst_data {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+};
+
struct en_clk_soc_data {
const struct clk_ops pcie_ops;
+ struct {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
+ u16 idx_map_nr;
+ } reset;
int (*hw_init)(struct platform_device *pdev, void __iomem *base,
void __iomem *np_base);
};
@@ -173,6 +192,69 @@ static const struct en_clk_desc en7523_b
}
};
+static const u16 en7581_rst_ofs[] = {
+ REG_RST_CTRL2,
+ REG_RST_CTRL1,
+};
+
+static const u16 en7581_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN7581_XPON_PHY_RST] = 0,
+ [EN7581_CPU_TIMER2_RST] = 2,
+ [EN7581_HSUART_RST] = 3,
+ [EN7581_UART4_RST] = 4,
+ [EN7581_UART5_RST] = 5,
+ [EN7581_I2C2_RST] = 6,
+ [EN7581_XSI_MAC_RST] = 7,
+ [EN7581_XSI_PHY_RST] = 8,
+ [EN7581_NPU_RST] = 9,
+ [EN7581_I2S_RST] = 10,
+ [EN7581_TRNG_RST] = 11,
+ [EN7581_TRNG_MSTART_RST] = 12,
+ [EN7581_DUAL_HSI0_RST] = 13,
+ [EN7581_DUAL_HSI1_RST] = 14,
+ [EN7581_HSI_RST] = 15,
+ [EN7581_DUAL_HSI0_MAC_RST] = 16,
+ [EN7581_DUAL_HSI1_MAC_RST] = 17,
+ [EN7581_HSI_MAC_RST] = 18,
+ [EN7581_WDMA_RST] = 19,
+ [EN7581_WOE0_RST] = 20,
+ [EN7581_WOE1_RST] = 21,
+ [EN7581_HSDMA_RST] = 22,
+ [EN7581_TDMA_RST] = 24,
+ [EN7581_EMMC_RST] = 25,
+ [EN7581_SOE_RST] = 26,
+ [EN7581_PCIE2_RST] = 27,
+ [EN7581_XFP_MAC_RST] = 28,
+ [EN7581_USB_HOST_P1_RST] = 29,
+ [EN7581_USB_HOST_P1_U3_PHY_RST] = 30,
+ /* RST_CTRL1 */
+ [EN7581_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN7581_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [EN7581_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [EN7581_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [EN7581_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN7581_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN7581_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN7581_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN7581_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN7581_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN7581_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN7581_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN7581_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN7581_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN7581_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN7581_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN7581_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN7581_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN7581_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN7581_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN7581_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
+ [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+};
+
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
@@ -375,7 +457,7 @@ static int en7581_clk_hw_init(struct pla
void __iomem *pb_base;
u32 val;
- pb_base = devm_platform_ioremap_resource(pdev, 2);
+ pb_base = devm_platform_ioremap_resource(pdev, 3);
if (IS_ERR(pb_base))
return PTR_ERR(pb_base);
@@ -428,6 +510,95 @@ static void en7523_register_clocks(struc
clk_data->num = EN7523_NUM_CLOCKS;
}
+static int en7523_reset_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
+ void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
+ u32 val;
+
+ val = readl(addr);
+ if (assert)
+ val |= BIT(id % RST_NR_PER_BANK);
+ else
+ val &= ~BIT(id % RST_NR_PER_BANK);
+ writel(val, addr);
+
+ return 0;
+}
+
+static int en7523_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return en7523_reset_update(rcdev, id, true);
+}
+
+static int en7523_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return en7523_reset_update(rcdev, id, false);
+}
+
+static int en7523_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
+ void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
+
+ return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
+}
+
+static int en7523_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
+
+ if (reset_spec->args[0] >= rcdev->nr_resets)
+ return -EINVAL;
+
+ return rst_data->idx_map[reset_spec->args[0]];
+}
+
+static const struct reset_control_ops en7523_reset_ops = {
+ .assert = en7523_reset_assert,
+ .deassert = en7523_reset_deassert,
+ .status = en7523_reset_status,
+};
+
+static int en7523_reset_register(struct platform_device *pdev,
+ const struct en_clk_soc_data *soc_data)
+{
+ struct device *dev = &pdev->dev;
+ struct en_rst_data *rst_data;
+ void __iomem *base;
+
+ /* no reset lines available */
+ if (!soc_data->reset.idx_map_nr)
+ return 0;
+
+ base = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
+ if (!rst_data)
+ return -ENOMEM;
+
+ rst_data->bank_ofs = soc_data->reset.bank_ofs;
+ rst_data->idx_map = soc_data->reset.idx_map;
+ rst_data->base = base;
+
+ rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr;
+ rst_data->rcdev.of_xlate = en7523_reset_xlate;
+ rst_data->rcdev.ops = &en7523_reset_ops;
+ rst_data->rcdev.of_node = dev->of_node;
+ rst_data->rcdev.of_reset_n_cells = 1;
+ rst_data->rcdev.owner = THIS_MODULE;
+ rst_data->rcdev.dev = dev;
+
+ return devm_reset_controller_register(dev, &rst_data->rcdev);
+}
+
static int en7523_clk_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -461,11 +632,17 @@ static int en7523_clk_probe(struct platf
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
+ return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n",
+ pdev->name);
+
+ r = en7523_reset_register(pdev, soc_data);
+ if (r) {
+ of_clk_del_provider(node);
+ return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n",
+ pdev->name);
+ }
- return r;
+ return 0;
}
static const struct en_clk_soc_data en7523_data = {
@@ -484,6 +661,11 @@ static const struct en_clk_soc_data en75
.unprepare = en7581_pci_unprepare,
.disable = en7581_pci_disable,
},
+ .reset = {
+ .bank_ofs = en7581_rst_ofs,
+ .idx_map = en7581_rst_map,
+ .idx_map_nr = ARRAY_SIZE(en7581_rst_map),
+ },
.hw_init = en7581_clk_hw_init,
};

View File

@ -0,0 +1,91 @@
From db7a4a11e8be375b0a9c159f688e0cea49eacc5d Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 27 Jun 2024 13:04:24 +0200
Subject: [PATCH 2/4] clk: en7523: Remove pcie prepare/unpreare callbacks for
EN7581 SoC
Get rid of prepare and unpreare callbacks for PCIe clock since they can
be modeled as a reset line cosumed by the PCIe driver
(pcie-mediatek-gen3)
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/16df149975514d3030499c48fc1c64f090093595.1719485847.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-en7523.c | 41 ++--------------------------------------
1 file changed, 2 insertions(+), 39 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -366,9 +366,8 @@ static struct clk_hw *en7523_register_pc
cg->base = np_base;
cg->hw.init = &init;
- if (init.ops->disable)
- init.ops->disable(&cg->hw);
- init.ops->unprepare(&cg->hw);
+ if (init.ops->unprepare)
+ init.ops->unprepare(&cg->hw);
if (clk_hw_register(dev, &cg->hw))
return NULL;
@@ -386,23 +385,6 @@ static int en7581_pci_is_enabled(struct
return (val & mask) == mask;
}
-static int en7581_pci_prepare(struct clk_hw *hw)
-{
- struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
- void __iomem *np_base = cg->base;
- u32 val, mask;
-
- mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
- REG_RESET_CONTROL_PCIEHB;
- val = readl(np_base + REG_RESET_CONTROL1);
- writel(val & ~mask, np_base + REG_RESET_CONTROL1);
- val = readl(np_base + REG_RESET_CONTROL2);
- writel(val & ~REG_RESET2_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
- usleep_range(5000, 10000);
-
- return 0;
-}
-
static int en7581_pci_enable(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
@@ -419,23 +401,6 @@ static int en7581_pci_enable(struct clk_
return 0;
}
-static void en7581_pci_unprepare(struct clk_hw *hw)
-{
- struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
- void __iomem *np_base = cg->base;
- u32 val, mask;
-
- mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
- REG_RESET_CONTROL_PCIEHB;
- val = readl(np_base + REG_RESET_CONTROL1);
- writel(val | mask, np_base + REG_RESET_CONTROL1);
- mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2;
- writel(val | mask, np_base + REG_RESET_CONTROL1);
- val = readl(np_base + REG_RESET_CONTROL2);
- writel(val | REG_RESET_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
- msleep(100);
-}
-
static void en7581_pci_disable(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
@@ -656,9 +621,7 @@ static const struct en_clk_soc_data en75
static const struct en_clk_soc_data en7581_data = {
.pcie_ops = {
.is_enabled = en7581_pci_is_enabled,
- .prepare = en7581_pci_prepare,
.enable = en7581_pci_enable,
- .unprepare = en7581_pci_unprepare,
.disable = en7581_pci_disable,
},
.reset = {

View File

@ -0,0 +1,65 @@
From bf288bd25d6232310abb81db417376ce460eb032 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 27 Jun 2024 13:04:25 +0200
Subject: [PATCH 3/4] clk: en7523: Remove PCIe reset open drain configuration
for EN7581
PCIe reset open drain configuration will be managed by pinctrl driver.
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/43276af5f08a554b4ab2e52e8d437fff5c06a732.1719485847.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-en7523.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -37,8 +37,6 @@
#define REG_PCIE1_MEM_MASK 0x0c
#define REG_PCIE2_MEM 0x10
#define REG_PCIE2_MEM_MASK 0x14
-#define REG_PCIE_RESET_OPEN_DRAIN 0x018c
-#define REG_PCIE_RESET_OPEN_DRAIN_MASK GENMASK(2, 0)
#define REG_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
@@ -86,8 +84,7 @@ struct en_clk_soc_data {
const u16 *idx_map;
u16 idx_map_nr;
} reset;
- int (*hw_init)(struct platform_device *pdev, void __iomem *base,
- void __iomem *np_base);
+ int (*hw_init)(struct platform_device *pdev, void __iomem *np_base);
};
static const u32 gsw_base[] = { 400000000, 500000000 };
@@ -416,7 +413,6 @@ static void en7581_pci_disable(struct cl
}
static int en7581_clk_hw_init(struct platform_device *pdev,
- void __iomem *base,
void __iomem *np_base)
{
void __iomem *pb_base;
@@ -439,10 +435,6 @@ static int en7581_clk_hw_init(struct pla
writel(0x28000000, pb_base + REG_PCIE2_MEM);
writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
- val = readl(base + REG_PCIE_RESET_OPEN_DRAIN);
- writel(val | REG_PCIE_RESET_OPEN_DRAIN_MASK,
- base + REG_PCIE_RESET_OPEN_DRAIN);
-
return 0;
}
@@ -582,7 +574,7 @@ static int en7523_clk_probe(struct platf
soc_data = device_get_match_data(&pdev->dev);
if (soc_data->hw_init) {
- r = soc_data->hw_init(pdev, base, np_base);
+ r = soc_data->hw_init(pdev, np_base);
if (r)
return r;
}

View File

@ -0,0 +1,93 @@
From 7aa291962f4c3b7afb9a12fa60b406b95e5eacb4 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 27 Jun 2024 13:04:22 +0200
Subject: [PATCH] dt-bindings: clock: airoha: Add reset support to EN7581 clock
binding
Introduce reset capability to EN7581 device-tree clock binding
documentation. Add reset register mapping between misc scu and pb scu
ones in order to follow the memory order. This change is not
introducing any backward compatibility issue since the EN7581 dts is not
upstream yet.
Fixes: 0a382be005cf ("dt-bindings: clock: airoha: add EN7581 binding")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/28fef3e83062d5d71e7b4be4b47583f851a15bf8.1719485847.git.lorenzo@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
.../bindings/clock/airoha,en7523-scu.yaml | 25 ++++++-
.../dt-bindings/reset/airoha,en7581-reset.h | 66 +++++++++++++++++++
2 files changed, 90 insertions(+), 1 deletion(-)
create mode 100644 include/dt-bindings/reset/airoha,en7581-reset.h
--- /dev/null
+++ b/include/dt-bindings/reset/airoha,en7581-reset.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 AIROHA Inc
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ */
+
+#ifndef __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7581_H_
+#define __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7581_H_
+
+/* RST_CTRL2 */
+#define EN7581_XPON_PHY_RST 0
+#define EN7581_CPU_TIMER2_RST 1
+#define EN7581_HSUART_RST 2
+#define EN7581_UART4_RST 3
+#define EN7581_UART5_RST 4
+#define EN7581_I2C2_RST 5
+#define EN7581_XSI_MAC_RST 6
+#define EN7581_XSI_PHY_RST 7
+#define EN7581_NPU_RST 8
+#define EN7581_I2S_RST 9
+#define EN7581_TRNG_RST 10
+#define EN7581_TRNG_MSTART_RST 11
+#define EN7581_DUAL_HSI0_RST 12
+#define EN7581_DUAL_HSI1_RST 13
+#define EN7581_HSI_RST 14
+#define EN7581_DUAL_HSI0_MAC_RST 15
+#define EN7581_DUAL_HSI1_MAC_RST 16
+#define EN7581_HSI_MAC_RST 17
+#define EN7581_WDMA_RST 18
+#define EN7581_WOE0_RST 19
+#define EN7581_WOE1_RST 20
+#define EN7581_HSDMA_RST 21
+#define EN7581_TDMA_RST 22
+#define EN7581_EMMC_RST 23
+#define EN7581_SOE_RST 24
+#define EN7581_PCIE2_RST 25
+#define EN7581_XFP_MAC_RST 26
+#define EN7581_USB_HOST_P1_RST 27
+#define EN7581_USB_HOST_P1_U3_PHY_RST 28
+/* RST_CTRL1 */
+#define EN7581_PCM1_ZSI_ISI_RST 29
+#define EN7581_FE_PDMA_RST 30
+#define EN7581_FE_QDMA_RST 31
+#define EN7581_PCM_SPIWP_RST 32
+#define EN7581_CRYPTO_RST 33
+#define EN7581_TIMER_RST 34
+#define EN7581_PCM1_RST 35
+#define EN7581_UART_RST 36
+#define EN7581_GPIO_RST 37
+#define EN7581_GDMA_RST 38
+#define EN7581_I2C_MASTER_RST 39
+#define EN7581_PCM2_ZSI_ISI_RST 40
+#define EN7581_SFC_RST 41
+#define EN7581_UART2_RST 42
+#define EN7581_GDMP_RST 43
+#define EN7581_FE_RST 44
+#define EN7581_USB_HOST_P0_RST 45
+#define EN7581_GSW_RST 46
+#define EN7581_SFC2_PCM_RST 47
+#define EN7581_PCIE0_RST 48
+#define EN7581_PCIE1_RST 49
+#define EN7581_CPU_TIMER_RST 50
+#define EN7581_PCIE_HB_RST 51
+#define EN7581_XPON_MAC_RST 52
+
+#endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7581_H_ */

View File

@ -0,0 +1,100 @@
From dc869a40d73ee6e9f47d683690ae507e30e56044 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 3 Jul 2024 18:12:42 +0200
Subject: [PATCH 1/3] PCI: mediatek-gen3: Add mtk_gen3_pcie_pdata data
structure
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce mtk_gen3_pcie_pdata data structure in order to define
multiple callbacks for each supported SoC.
This is a preliminary patch to introduce EN7581 PCIe support.
Link: https://lore.kernel.org/linux-pci/c193d1a87505d045e2e0ef33317bce17012ee095.1720022580.git.lorenzo@kernel.org
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Jianjun Wang <jianjun.wang@mediatek.com>
---
drivers/pci/controller/pcie-mediatek-gen3.c | 24 ++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -100,6 +100,16 @@
#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)
#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)
+struct mtk_gen3_pcie;
+
+/**
+ * struct mtk_gen3_pcie_pdata - differentiate between host generations
+ * @power_up: pcie power_up callback
+ */
+struct mtk_gen3_pcie_pdata {
+ int (*power_up)(struct mtk_gen3_pcie *pcie);
+};
+
/**
* struct mtk_msi_set - MSI information for each set
* @base: IO mapped register base
@@ -131,6 +141,7 @@ struct mtk_msi_set {
* @msi_sets: MSI sets information
* @lock: lock protecting IRQ bit map
* @msi_irq_in_use: bit map for assigned MSI IRQ
+ * @soc: pointer to SoC-dependent operations
*/
struct mtk_gen3_pcie {
struct device *dev;
@@ -151,6 +162,8 @@ struct mtk_gen3_pcie {
struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM];
struct mutex lock;
DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM);
+
+ const struct mtk_gen3_pcie_pdata *soc;
};
/* LTSSM state in PCIE_LTSSM_STATUS_REG bit[28:24] */
@@ -904,7 +917,7 @@ static int mtk_pcie_setup(struct mtk_gen
usleep_range(10, 20);
/* Don't touch the hardware registers before power up */
- err = mtk_pcie_power_up(pcie);
+ err = pcie->soc->power_up(pcie);
if (err)
return err;
@@ -939,6 +952,7 @@ static int mtk_pcie_probe(struct platfor
pcie = pci_host_bridge_priv(host);
pcie->dev = dev;
+ pcie->soc = device_get_match_data(dev);
platform_set_drvdata(pdev, pcie);
err = mtk_pcie_setup(pcie);
@@ -1054,7 +1068,7 @@ static int mtk_pcie_resume_noirq(struct
struct mtk_gen3_pcie *pcie = dev_get_drvdata(dev);
int err;
- err = mtk_pcie_power_up(pcie);
+ err = pcie->soc->power_up(pcie);
if (err)
return err;
@@ -1074,8 +1088,12 @@ static const struct dev_pm_ops mtk_pcie_
mtk_pcie_resume_noirq)
};
+static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_mt8192 = {
+ .power_up = mtk_pcie_power_up,
+};
+
static const struct of_device_id mtk_pcie_of_match[] = {
- { .compatible = "mediatek,mt8192-pcie" },
+ { .compatible = "mediatek,mt8192-pcie", .data = &mtk_pcie_soc_mt8192 },
{},
};
MODULE_DEVICE_TABLE(of, mtk_pcie_of_match);

View File

@ -0,0 +1,155 @@
From ee9eabbe3f0f0c7458d89840add97e54d4e0bccf Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 3 Jul 2024 18:12:43 +0200
Subject: [PATCH 2/3] PCI: mediatek-gen3: Rely on reset_bulk APIs for PHY reset
lines
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use reset_bulk APIs to manage PHY reset lines.
This is a preliminary patch in order to add Airoha EN7581 PCIe support.
Link: https://lore.kernel.org/linux-pci/3ceb83bc0defbcf868521f8df4b9100e55ec2614.1720022580.git.lorenzo@kernel.org
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Jianjun Wang <jianjun.wang@mediatek.com>
---
drivers/pci/controller/pcie-mediatek-gen3.c | 45 +++++++++++++++------
1 file changed, 33 insertions(+), 12 deletions(-)
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -100,14 +100,21 @@
#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)
#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)
+#define MAX_NUM_PHY_RESETS 1
+
struct mtk_gen3_pcie;
/**
* struct mtk_gen3_pcie_pdata - differentiate between host generations
* @power_up: pcie power_up callback
+ * @phy_resets: phy reset lines SoC data.
*/
struct mtk_gen3_pcie_pdata {
int (*power_up)(struct mtk_gen3_pcie *pcie);
+ struct {
+ const char *id[MAX_NUM_PHY_RESETS];
+ int num_resets;
+ } phy_resets;
};
/**
@@ -128,7 +135,7 @@ struct mtk_msi_set {
* @base: IO mapped register base
* @reg_base: physical register base
* @mac_reset: MAC reset control
- * @phy_reset: PHY reset control
+ * @phy_resets: PHY reset controllers
* @phy: PHY controller block
* @clks: PCIe clocks
* @num_clks: PCIe clocks count for this port
@@ -148,7 +155,7 @@ struct mtk_gen3_pcie {
void __iomem *base;
phys_addr_t reg_base;
struct reset_control *mac_reset;
- struct reset_control *phy_reset;
+ struct reset_control_bulk_data phy_resets[MAX_NUM_PHY_RESETS];
struct phy *phy;
struct clk_bulk_data *clks;
int num_clks;
@@ -788,10 +795,10 @@ static int mtk_pcie_setup_irq(struct mtk
static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie)
{
+ int i, ret, num_resets = pcie->soc->phy_resets.num_resets;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
struct resource *regs;
- int ret;
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac");
if (!regs)
@@ -804,12 +811,12 @@ static int mtk_pcie_parse_port(struct mt
pcie->reg_base = regs->start;
- pcie->phy_reset = devm_reset_control_get_optional_exclusive(dev, "phy");
- if (IS_ERR(pcie->phy_reset)) {
- ret = PTR_ERR(pcie->phy_reset);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to get PHY reset\n");
+ for (i = 0; i < num_resets; i++)
+ pcie->phy_resets[i].id = pcie->soc->phy_resets.id[i];
+ ret = devm_reset_control_bulk_get_optional_shared(dev, num_resets, pcie->phy_resets);
+ if (ret) {
+ dev_err(dev, "failed to get PHY bulk reset\n");
return ret;
}
@@ -846,7 +853,11 @@ static int mtk_pcie_power_up(struct mtk_
int err;
/* PHY power on and enable pipe clock */
- reset_control_deassert(pcie->phy_reset);
+ err = reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
+ if (err) {
+ dev_err(dev, "failed to deassert PHYs\n");
+ return err;
+ }
err = phy_init(pcie->phy);
if (err) {
@@ -882,7 +893,7 @@ err_clk_init:
err_phy_on:
phy_exit(pcie->phy);
err_phy_init:
- reset_control_assert(pcie->phy_reset);
+ reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
return err;
}
@@ -897,7 +908,7 @@ static void mtk_pcie_power_down(struct m
phy_power_off(pcie->phy);
phy_exit(pcie->phy);
- reset_control_assert(pcie->phy_reset);
+ reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
}
static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie)
@@ -909,10 +920,16 @@ static int mtk_pcie_setup(struct mtk_gen
return err;
/*
+ * Deassert the line in order to avoid unbalance in deassert_count
+ * counter since the bulk is shared.
+ */
+ reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
+ /*
* The controller may have been left out of reset by the bootloader
* so make sure that we get a clean start by asserting resets here.
*/
- reset_control_assert(pcie->phy_reset);
+ reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
+
reset_control_assert(pcie->mac_reset);
usleep_range(10, 20);
@@ -1090,6 +1107,10 @@ static const struct dev_pm_ops mtk_pcie_
static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_mt8192 = {
.power_up = mtk_pcie_power_up,
+ .phy_resets = {
+ .id[0] = "phy",
+ .num_resets = 1,
+ },
};
static const struct of_device_id mtk_pcie_of_match[] = {

View File

@ -0,0 +1,199 @@
From f6ab898356dd70f267c49045a79d28ea5cf5e43e Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 3 Jul 2024 18:12:44 +0200
Subject: [PATCH 3/3] PCI: mediatek-gen3: Add Airoha EN7581 support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce support for Airoha EN7581 PCIe controller to mediatek-gen3
PCIe controller driver.
Link: https://lore.kernel.org/linux-pci/aca00bd672ee576ad96d279414fc0835ff31f637.1720022580.git.lorenzo@kernel.org
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Tested-by: Zhengping Zhang <zhengping.zhang@airoha.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Jianjun Wang <jianjun.wang@mediatek.com>
---
drivers/pci/controller/Kconfig | 2 +-
drivers/pci/controller/pcie-mediatek-gen3.c | 113 +++++++++++++++++++-
2 files changed, 113 insertions(+), 2 deletions(-)
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -196,7 +196,7 @@ config PCIE_MEDIATEK
config PCIE_MEDIATEK_GEN3
tristate "MediaTek Gen3 PCIe controller"
- depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
depends on PCI_MSI
help
Adds support for PCIe Gen3 MAC controller for MediaTek SoCs.
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -6,7 +6,9 @@
* Author: Jianjun Wang <jianjun.wang@mediatek.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
@@ -15,6 +17,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/msi.h>
+#include <linux/of_device.h>
+#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@@ -29,6 +33,12 @@
#define PCI_CLASS(class) (class << 8)
#define PCIE_RC_MODE BIT(0)
+#define PCIE_EQ_PRESET_01_REG 0x100
+#define PCIE_VAL_LN0_DOWNSTREAM GENMASK(6, 0)
+#define PCIE_VAL_LN0_UPSTREAM GENMASK(14, 8)
+#define PCIE_VAL_LN1_DOWNSTREAM GENMASK(22, 16)
+#define PCIE_VAL_LN1_UPSTREAM GENMASK(30, 24)
+
#define PCIE_CFGNUM_REG 0x140
#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0))
#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8))
@@ -68,6 +78,14 @@
#define PCIE_MSI_SET_ENABLE_REG 0x190
#define PCIE_MSI_SET_ENABLE GENMASK(PCIE_MSI_SET_NUM - 1, 0)
+#define PCIE_PIPE4_PIE8_REG 0x338
+#define PCIE_K_FINETUNE_MAX GENMASK(5, 0)
+#define PCIE_K_FINETUNE_ERR GENMASK(7, 6)
+#define PCIE_K_PRESET_TO_USE GENMASK(18, 8)
+#define PCIE_K_PHYPARAM_QUERY BIT(19)
+#define PCIE_K_QUERY_TIMEOUT BIT(20)
+#define PCIE_K_PRESET_TO_USE_16G GENMASK(31, 21)
+
#define PCIE_MSI_SET_BASE_REG 0xc00
#define PCIE_MSI_SET_OFFSET 0x10
#define PCIE_MSI_SET_STATUS_OFFSET 0x04
@@ -100,7 +118,10 @@
#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)
#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)
-#define MAX_NUM_PHY_RESETS 1
+#define MAX_NUM_PHY_RESETS 3
+
+/* Time in ms needed to complete PCIe reset on EN7581 SoC */
+#define PCIE_EN7581_RESET_TIME_MS 100
struct mtk_gen3_pcie;
@@ -847,6 +868,85 @@ static int mtk_pcie_parse_port(struct mt
return 0;
}
+static int mtk_pcie_en7581_power_up(struct mtk_gen3_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ int err;
+ u32 val;
+
+ /*
+ * Wait for the time needed to complete the bulk assert in
+ * mtk_pcie_setup for EN7581 SoC.
+ */
+ mdelay(PCIE_EN7581_RESET_TIME_MS);
+
+ err = phy_init(pcie->phy);
+ if (err) {
+ dev_err(dev, "failed to initialize PHY\n");
+ return err;
+ }
+
+ err = phy_power_on(pcie->phy);
+ if (err) {
+ dev_err(dev, "failed to power on PHY\n");
+ goto err_phy_on;
+ }
+
+ err = reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
+ if (err) {
+ dev_err(dev, "failed to deassert PHYs\n");
+ goto err_phy_deassert;
+ }
+
+ /*
+ * Wait for the time needed to complete the bulk de-assert above.
+ * This time is specific for EN7581 SoC.
+ */
+ mdelay(PCIE_EN7581_RESET_TIME_MS);
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ err = clk_bulk_prepare(pcie->num_clks, pcie->clks);
+ if (err) {
+ dev_err(dev, "failed to prepare clock\n");
+ goto err_clk_prepare;
+ }
+
+ val = FIELD_PREP(PCIE_VAL_LN0_DOWNSTREAM, 0x47) |
+ FIELD_PREP(PCIE_VAL_LN1_DOWNSTREAM, 0x47) |
+ FIELD_PREP(PCIE_VAL_LN0_UPSTREAM, 0x41) |
+ FIELD_PREP(PCIE_VAL_LN1_UPSTREAM, 0x41);
+ writel_relaxed(val, pcie->base + PCIE_EQ_PRESET_01_REG);
+
+ val = PCIE_K_PHYPARAM_QUERY | PCIE_K_QUERY_TIMEOUT |
+ FIELD_PREP(PCIE_K_PRESET_TO_USE_16G, 0x80) |
+ FIELD_PREP(PCIE_K_PRESET_TO_USE, 0x2) |
+ FIELD_PREP(PCIE_K_FINETUNE_MAX, 0xf);
+ writel_relaxed(val, pcie->base + PCIE_PIPE4_PIE8_REG);
+
+ err = clk_bulk_enable(pcie->num_clks, pcie->clks);
+ if (err) {
+ dev_err(dev, "failed to prepare clock\n");
+ goto err_clk_enable;
+ }
+
+ return 0;
+
+err_clk_enable:
+ clk_bulk_unprepare(pcie->num_clks, pcie->clks);
+err_clk_prepare:
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
+err_phy_deassert:
+ phy_power_off(pcie->phy);
+err_phy_on:
+ phy_exit(pcie->phy);
+
+ return err;
+}
+
static int mtk_pcie_power_up(struct mtk_gen3_pcie *pcie)
{
struct device *dev = pcie->dev;
@@ -1113,7 +1213,18 @@ static const struct mtk_gen3_pcie_pdata
},
};
+static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_en7581 = {
+ .power_up = mtk_pcie_en7581_power_up,
+ .phy_resets = {
+ .id[0] = "phy-lane0",
+ .id[1] = "phy-lane1",
+ .id[2] = "phy-lane2",
+ .num_resets = 3,
+ },
+};
+
static const struct of_device_id mtk_pcie_of_match[] = {
+ { .compatible = "airoha,en7581-pcie", .data = &mtk_pcie_soc_en7581 },
{ .compatible = "mediatek,mt8192-pcie", .data = &mtk_pcie_soc_mt8192 },
{},
};

View File

@ -0,0 +1,112 @@
From 2a011c3c12e8de461fb1fdce85fa38d308c4eb8b Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 29 Jun 2024 19:51:49 +0200
Subject: [PATCH] phy: airoha: Add dtime and Rx AEQ IO registers
Introduce Tx-Rx detection Time and Rx AEQ training mappings to
phy-airoha-pcie driver. This is a preliminary patch to introduce PCIe
support to En7581 SoC through the mediatek-gen3 PCIe driver.
This change is not introducing any backward compatibility issue since
the EN7581 dts is not upstream yet.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/edf3b28926177166c65256604d69f2f576cb6fb3.1719682943.git.lorenzo@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/phy/phy-airoha-pcie-regs.h | 17 +++++++++++++
drivers/phy/phy-airoha-pcie.c | 38 ++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
--- a/drivers/phy/phy-airoha-pcie-regs.h
+++ b/drivers/phy/phy-airoha-pcie-regs.h
@@ -474,4 +474,21 @@
#define REG_PCIE_PMA_DIG_RESERVE_27 0x0908
#define REG_PCIE_PMA_DIG_RESERVE_30 0x0914
+/* DTIME */
+#define REG_PCIE_PEXTP_DIG_GLB44 0x00
+#define PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL GENMASK(7, 0)
+#define PCIE_XTP_RXDET_EN_STB_T_SEL GENMASK(15, 8)
+#define PCIE_XTP_RXDET_FINISH_STB_T_SEL GENMASK(23, 16)
+#define PCIE_XTP_TXPD_TX_DATA_EN_DLY GENMASK(27, 24)
+#define PCIE_XTP_TXPD_RXDET_DONE_CDT BIT(28)
+#define PCIE_XTP_RXDET_LATCH_STB_T_SEL GENMASK(31, 29)
+
+/* RX AEQ */
+#define REG_PCIE_PEXTP_DIG_LN_RX30_P0 0x0000
+#define PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT GENMASK(7, 0)
+#define PCIE_XTP_LN_RX_PDOWN_T2RLB_DIG_EN BIT(8)
+#define PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT GENMASK(31, 16)
+
+#define REG_PCIE_PEXTP_DIG_LN_RX30_P1 0x0100
+
#endif /* _PHY_AIROHA_PCIE_H */
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/phy-airoha-pcie.c
@@ -31,6 +31,9 @@ enum airoha_pcie_port_gen {
* @csr_2l: Analogic lane IO mapped register base address
* @pma0: IO mapped register base address of PMA0-PCIe
* @pma1: IO mapped register base address of PMA1-PCIe
+ * @p0_xr_dtime: IO mapped register base address of port0 Tx-Rx detection time
+ * @p1_xr_dtime: IO mapped register base address of port1 Tx-Rx detection time
+ * @rx_aeq: IO mapped register base address of Rx AEQ training
*/
struct airoha_pcie_phy {
struct device *dev;
@@ -38,6 +41,9 @@ struct airoha_pcie_phy {
void __iomem *csr_2l;
void __iomem *pma0;
void __iomem *pma1;
+ void __iomem *p0_xr_dtime;
+ void __iomem *p1_xr_dtime;
+ void __iomem *rx_aeq;
};
static void airoha_phy_clear_bits(void __iomem *reg, u32 mask)
@@ -1101,6 +1107,21 @@ static void airoha_pcie_phy_load_kflow(s
static int airoha_pcie_phy_init(struct phy *phy)
{
struct airoha_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ /* Setup Tx-Rx detection time */
+ val = FIELD_PREP(PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL, 0x33) |
+ FIELD_PREP(PCIE_XTP_RXDET_EN_STB_T_SEL, 0x1) |
+ FIELD_PREP(PCIE_XTP_RXDET_FINISH_STB_T_SEL, 0x2) |
+ FIELD_PREP(PCIE_XTP_TXPD_TX_DATA_EN_DLY, 0x3) |
+ FIELD_PREP(PCIE_XTP_RXDET_LATCH_STB_T_SEL, 0x1);
+ writel(val, pcie_phy->p0_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44);
+ writel(val, pcie_phy->p1_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44);
+ /* Setup Rx AEQ training time */
+ val = FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT, 0x32) |
+ FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT, 0x5050);
+ writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P0);
+ writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P1);
/* enable load FLL-K flow */
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_14,
@@ -1217,6 +1238,23 @@ static int airoha_pcie_phy_probe(struct
return dev_err_probe(dev, PTR_ERR(pcie_phy->phy),
"Failed to create PCIe phy\n");
+ pcie_phy->p0_xr_dtime =
+ devm_platform_ioremap_resource_byname(pdev, "p0-xr-dtime");
+ if (IS_ERR(pcie_phy->p0_xr_dtime))
+ return dev_err_probe(dev, PTR_ERR(pcie_phy->p0_xr_dtime),
+ "Failed to map P0 Tx-Rx dtime base\n");
+
+ pcie_phy->p1_xr_dtime =
+ devm_platform_ioremap_resource_byname(pdev, "p1-xr-dtime");
+ if (IS_ERR(pcie_phy->p1_xr_dtime))
+ return dev_err_probe(dev, PTR_ERR(pcie_phy->p1_xr_dtime),
+ "Failed to map P1 Tx-Rx dtime base\n");
+
+ pcie_phy->rx_aeq = devm_platform_ioremap_resource_byname(pdev, "rx-aeq");
+ if (IS_ERR(pcie_phy->rx_aeq))
+ return dev_err_probe(dev, PTR_ERR(pcie_phy->rx_aeq),
+ "Failed to map Rx AEQ base\n");
+
pcie_phy->dev = dev;
phy_set_drvdata(pcie_phy->phy, pcie_phy);

View File

@ -0,0 +1,40 @@
From 7f7315db3d262298ab33d198d3f0b09cabfa7b6b Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 6 Aug 2024 17:55:48 +0200
Subject: [PATCH] phy: airoha: adjust initialization delay in
airoha_pcie_phy_init()
Align phy-pcie initialization delay to the vendor sdk in
airoha_pcie_phy_init routine and allow the hw to complete required
configuration before proceeding
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/8af6f27857619f1e0dd227f08b8584ae8fb22fb2.1722959625.git.lorenzo@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/phy/phy-airoha-pcie.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/phy-airoha-pcie.c
@@ -18,6 +18,9 @@
#define LEQ_LEN_CTRL_MAX_VAL 7
#define FREQ_LOCK_MAX_ATTEMPT 10
+/* PCIe-PHY initialization time in ms needed by the hw to complete */
+#define PHY_HW_INIT_TIME_MS 30
+
enum airoha_pcie_port_gen {
PCIE_PORT_GEN1 = 1,
PCIE_PORT_GEN2,
@@ -1181,7 +1184,8 @@ static int airoha_pcie_phy_init(struct p
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0,
PCIE_DA_XPON_CDR_PR_PWDB);
- usleep_range(100, 200);
+ /* Wait for the PCIe PHY to complete initialization before returning */
+ msleep(PHY_HW_INIT_TIME_MS);
return 0;
}

View File

@ -0,0 +1,26 @@
From ca9afde0563a80200eab856a53d7eab28c8fdd90 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 18 Sep 2024 15:32:52 +0200
Subject: [PATCH 1/4] phy: airoha: Fix REG_CSR_2L_PLL_CMN_RESERVE0 config in
airoha_pcie_phy_init_clk_out()
Fix typo configuring REG_CSR_2L_PLL_CMN_RESERVE0 register in
airoha_pcie_phy_init_clk_out routine.
Fixes: d7d2818b9383 ("phy: airoha: Add PCIe PHY driver for EN7581 SoC.")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/phy/phy-airoha-pcie.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/phy-airoha-pcie.c
@@ -459,7 +459,7 @@ static void airoha_pcie_phy_init_clk_out
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET,
CSR_2L_PXP_CLKTX1_SR);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_PLL_CMN_RESERVE0,
- CSR_2L_PXP_PLL_RESERVE_MASK, 0xdd);
+ CSR_2L_PXP_PLL_RESERVE_MASK, 0xd0d);
}
static void airoha_pcie_phy_init_csr_2l(struct airoha_pcie_phy *pcie_phy)

View File

@ -0,0 +1,29 @@
From 2c2313c84ad7c0e5e39fbd98559d40f6b9ec1f83 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 18 Sep 2024 15:32:53 +0200
Subject: [PATCH 2/4] phy: airoha: Fix REG_PCIE_PMA_TX_RESET config in
airoha_pcie_phy_init_csr_2l()
Fix typos configuring REG_PCIE_PMA_TX_RESET register in
airoha_pcie_phy_init_csr_2l routine for lane0 and lane1
Fixes: d7d2818b9383 ("phy: airoha: Add PCIe PHY driver for EN7581 SoC.")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/phy/phy-airoha-pcie.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/phy-airoha-pcie.c
@@ -471,9 +471,9 @@ static void airoha_pcie_phy_init_csr_2l(
PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST |
PCIE_SW_RX_RST);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET,
- PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET);
+ PCIE_TX_TOP_RST | PCIE_TX_CAL_RST);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET,
- PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET);
+ PCIE_TX_TOP_RST | PCIE_TX_CAL_RST);
}
static void airoha_pcie_phy_init_rx(struct airoha_pcie_phy *pcie_phy)

View File

@ -0,0 +1,26 @@
From 6e0c349a8a59959c3d3571b5f6776bc2d2ca62bc Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 18 Sep 2024 15:32:54 +0200
Subject: [PATCH 3/4] phy: airoha: Fix REG_CSR_2L_JCPLL_SDM_HREN config in
airoha_pcie_phy_init_ssc_jcpll()
Fix typo configuring REG_CSR_2L_JCPLL_SDM_HREN register in
airoha_pcie_phy_init_ssc_jcpll routine.
Fixes: d7d2818b9383 ("phy: airoha: Add PCIe PHY driver for EN7581 SoC.")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/phy/phy-airoha-pcie.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/phy-airoha-pcie.c
@@ -802,7 +802,7 @@ static void airoha_pcie_phy_init_ssc_jcp
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_IFM,
CSR_2L_PXP_JCPLL_SDM_IFM);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN,
- REG_CSR_2L_JCPLL_SDM_HREN);
+ CSR_2L_PXP_JCPLL_SDM_HREN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY,
CSR_2L_PXP_JCPLL_SDM_DI_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,

View File

@ -0,0 +1,32 @@
From bc1bb265f504ea19ce611a1aec1a40dec409cd15 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 18 Sep 2024 15:32:55 +0200
Subject: [PATCH 4/4] phy: airoha: Fix REG_CSR_2L_RX{0,1}_REV0 definitions
Fix the following register definitions for REG_CSR_2L_RX{0,1}_REV0
registers:
- CSR_2L_PXP_VOS_PNINV
- CSR_2L_PXP_FE_GAIN_NORMAL_MODE
- CSR_2L_PXP_FE_GAIN_TRAIN_MODE
Fixes: d7d2818b9383 ("phy: airoha: Add PCIe PHY driver for EN7581 SoC.")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/phy/phy-airoha-pcie-regs.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/phy/phy-airoha-pcie-regs.h
+++ b/drivers/phy/phy-airoha-pcie-regs.h
@@ -197,9 +197,9 @@
#define CSR_2L_PXP_TX1_MULTLANE_EN BIT(0)
#define REG_CSR_2L_RX0_REV0 0x00fc
-#define CSR_2L_PXP_VOS_PNINV GENMASK(3, 2)
-#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(6, 4)
-#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(10, 8)
+#define CSR_2L_PXP_VOS_PNINV GENMASK(19, 18)
+#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(22, 20)
+#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(26, 24)
#define REG_CSR_2L_RX0_PHYCK_DIV 0x0100
#define CSR_2L_PXP_RX0_PHYCK_SEL GENMASK(9, 8)

View File

@ -0,0 +1,55 @@
From 2e6bbfe7b0c0607001b784082c2685b134174fac Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Fri, 13 Sep 2024 23:07:13 +0200
Subject: [PATCH 1/2] spi: airoha: fix dirmap_{read,write} operations
SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end of
dirmap_read operation even if it is already set.
In the same way, SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the
end of dirmap_write operation even if it is already set.
For this reason use regmap_write_bits() instead of regmap_set_bits().
This patch fixes mtd_pagetest kernel module test.
Fixes: a403997c1201 ("spi: airoha: add SPI-NAND Flash controller driver")
Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240913-airoha-spi-fixes-v1-1-de2e74ed4664@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-airoha-snfi.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -739,8 +739,13 @@ static ssize_t airoha_snand_dirmap_read(
if (err)
return err;
- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
- SPI_NFI_READ_FROM_CACHE_DONE);
+ /*
+ * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
+ * of dirmap_read operation even if it is already set.
+ */
+ err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_READ_FROM_CACHE_DONE,
+ SPI_NFI_READ_FROM_CACHE_DONE);
if (err)
return err;
@@ -870,8 +875,13 @@ static ssize_t airoha_snand_dirmap_write
if (err)
return err;
- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
- SPI_NFI_LOAD_TO_CACHE_DONE);
+ /*
+ * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
+ * of dirmap_write operation even if it is already set.
+ */
+ err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_LOAD_TO_CACHE_DONE,
+ SPI_NFI_LOAD_TO_CACHE_DONE);
if (err)
return err;

View File

@ -0,0 +1,39 @@
From 0e58637eb968c636725dcd6c7055249b4e5326fb Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Fri, 13 Sep 2024 23:07:14 +0200
Subject: [PATCH 2/2] spi: airoha: fix airoha_snand_{write,read}_data data_len
estimation
Fix data length written and read in airoha_snand_write_data and
airoha_snand_read_data routines respectively if it is bigger than
SPI_MAX_TRANSFER_SIZE.
Fixes: a403997c1201 ("spi: airoha: add SPI-NAND Flash controller driver")
Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240913-airoha-spi-fixes-v1-2-de2e74ed4664@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-airoha-snfi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -405,7 +405,7 @@ static int airoha_snand_write_data(struc
for (i = 0; i < len; i += data_len) {
int err;
- data_len = min(len, SPI_MAX_TRANSFER_SIZE);
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
if (err)
return err;
@@ -427,7 +427,7 @@ static int airoha_snand_read_data(struct
for (i = 0; i < len; i += data_len) {
int err;
- data_len = min(len, SPI_MAX_TRANSFER_SIZE);
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len);
if (err)
return err;

View File

@ -0,0 +1,116 @@
From fffca269e4f31c3633c6d810833ba1b184407915 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 19 Sep 2024 18:57:16 +0200
Subject: [PATCH] spi: airoha: remove read cache in airoha_snand_dirmap_read()
Current upstream driver reports errors running mtd_oobtest kernel module
test:
root@OpenWrt:/# insmod mtd_test.ko
root@OpenWrt:/# insmod mtd_oobtest.ko dev=5
[ 7023.730584] =================================================
[ 7023.736399] mtd_oobtest: MTD device: 5
[ 7023.740160] mtd_oobtest: MTD device size 3670016, eraseblock size 131072, page size 2048, count of eraseblocks 28, pages per eraseblock 64, OOB size 128
[ 7023.753837] mtd_test: scanning for bad eraseblocks
[ 7023.758636] mtd_test: scanned 28 eraseblocks, 0 are bad
[ 7023.763861] mtd_oobtest: test 1 of 5
[ 7024.042076] mtd_oobtest: writing OOBs of whole device
[ 7024.682069] mtd_oobtest: written up to eraseblock 0
[ 7041.962077] mtd_oobtest: written 28 eraseblocks
[ 7041.966626] mtd_oobtest: verifying all eraseblocks
[ 7041.972276] mtd_oobtest: error @addr[0x0:0x0] 0xff -> 0xe diff 0xf1
[ 7041.978550] mtd_oobtest: error @addr[0x0:0x1] 0xff -> 0x10 diff 0xef
[ 7041.984932] mtd_oobtest: error @addr[0x0:0x2] 0xff -> 0x82 diff 0x7d
[ 7041.991293] mtd_oobtest: error @addr[0x0:0x3] 0xff -> 0x10 diff 0xef
[ 7041.997659] mtd_oobtest: error @addr[0x0:0x4] 0xff -> 0x0 diff 0xff
[ 7042.003942] mtd_oobtest: error @addr[0x0:0x5] 0xff -> 0x8a diff 0x75
[ 7042.010294] mtd_oobtest: error @addr[0x0:0x6] 0xff -> 0x20 diff 0xdf
[ 7042.016659] mtd_oobtest: error @addr[0x0:0x7] 0xff -> 0x1 diff 0xfe
[ 7042.022935] mtd_oobtest: error @addr[0x0:0x8] 0xff -> 0x2e diff 0xd1
[ 7042.029295] mtd_oobtest: error @addr[0x0:0x9] 0xff -> 0x40 diff 0xbf
[ 7042.035661] mtd_oobtest: error @addr[0x0:0xa] 0xff -> 0x0 diff 0xff
[ 7042.041935] mtd_oobtest: error @addr[0x0:0xb] 0xff -> 0x89 diff 0x76
[ 7042.048300] mtd_oobtest: error @addr[0x0:0xc] 0xff -> 0x82 diff 0x7d
[ 7042.054662] mtd_oobtest: error @addr[0x0:0xd] 0xff -> 0x15 diff 0xea
[ 7042.061014] mtd_oobtest: error @addr[0x0:0xe] 0xff -> 0x90 diff 0x6f
[ 7042.067380] mtd_oobtest: error @addr[0x0:0xf] 0xff -> 0x0 diff 0xff
....
[ 7432.421369] mtd_oobtest: error @addr[0x237800:0x36] 0xff -> 0x5f diff 0xa0
[ 7432.428242] mtd_oobtest: error @addr[0x237800:0x37] 0xff -> 0x21 diff 0xde
[ 7432.435118] mtd_oobtest: error: verify failed at 0x237800
[ 7432.440510] mtd_oobtest: error: too many errors
[ 7432.445053] mtd_oobtest: error -1 occurred
The above errors are due to the buggy logic in the 'read cache' available
in airoha_snand_dirmap_read() routine since there are some corner cases
where we are missing data updates. Since we do not get any read/write speed
improvement using the cache (according to the mtd_speedtest kernel
module test), in order to fix the mtd_oobtest test, remove the 'read cache'
in airoha_snand_dirmap_read routine. Now the driver is passing all the
tests available in mtd_test suite.
Fixes: a403997c1201 ("spi: airoha: add SPI-NAND Flash controller driver")
Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240919-airoha-spi-fixes-v2-1-cb0f0ed9920a@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-airoha-snfi.c | 21 ---------------------
1 file changed, 21 deletions(-)
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -211,9 +211,6 @@ struct airoha_snand_dev {
u8 *txrx_buf;
dma_addr_t dma_addr;
-
- u64 cur_page_num;
- bool data_need_update;
};
struct airoha_snand_ctrl {
@@ -644,11 +641,6 @@ static ssize_t airoha_snand_dirmap_read(
u32 val, rd_mode;
int err;
- if (!as_dev->data_need_update)
- return len;
-
- as_dev->data_need_update = false;
-
switch (op->cmd.opcode) {
case SPI_NAND_OP_READ_FROM_CACHE_DUAL:
rd_mode = 1;
@@ -895,23 +887,11 @@ static ssize_t airoha_snand_dirmap_write
static int airoha_snand_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct airoha_snand_dev *as_dev = spi_get_ctldata(mem->spi);
u8 data[8], cmd, opcode = op->cmd.opcode;
struct airoha_snand_ctrl *as_ctrl;
int i, err;
as_ctrl = spi_controller_get_devdata(mem->spi->controller);
- if (opcode == SPI_NAND_OP_PROGRAM_EXECUTE &&
- op->addr.val == as_dev->cur_page_num) {
- as_dev->data_need_update = true;
- } else if (opcode == SPI_NAND_OP_PAGE_READ) {
- if (!as_dev->data_need_update &&
- op->addr.val == as_dev->cur_page_num)
- return 0;
-
- as_dev->data_need_update = true;
- as_dev->cur_page_num = op->addr.val;
- }
/* switch to manual mode */
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
@@ -996,7 +976,6 @@ static int airoha_snand_setup(struct spi
if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr))
return -ENOMEM;
- as_dev->data_need_update = true;
spi_set_ctldata(spi, as_dev);
return 0;

View File

@ -0,0 +1,435 @@
From 7a4b3ebf1d60349587fee21872536e7bd6a4cf39 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sun, 22 Sep 2024 19:38:30 +0200
Subject: [PATCH] spi: airoha: do not keep {tx,rx} dma buffer always mapped
DMA map txrx_buf on demand in airoha_snand_dirmap_read and
airoha_snand_dirmap_write routines and do not keep it always mapped.
This patch is not fixing any bug or introducing any functional change
to the driver, it just simplifies the code and improve code readability
without introducing any performance degradation according to the results
obtained from the mtd_speedtest kernel module test.
root@OpenWrt:# insmod mtd_test.ko
root@OpenWrt:# insmod mtd_speedtest.ko dev=5
[ 49.849869] =================================================
[ 49.855659] mtd_speedtest: MTD device: 5
[ 49.859583] mtd_speedtest: MTD device size 8388608, eraseblock size 131072, page size 2048, count of eraseblocks 64, pages per eraseblock 64, OOB size 128
[ 49.874622] mtd_test: scanning for bad eraseblocks
[ 49.879433] mtd_test: scanned 64 eraseblocks, 0 are bad
[ 50.106372] mtd_speedtest: testing eraseblock write speed
[ 53.083380] mtd_speedtest: eraseblock write speed is 2756 KiB/s
[ 53.089322] mtd_speedtest: testing eraseblock read speed
[ 54.143360] mtd_speedtest: eraseblock read speed is 7811 KiB/s
[ 54.370365] mtd_speedtest: testing page write speed
[ 57.349480] mtd_speedtest: page write speed is 2754 KiB/s
[ 57.354895] mtd_speedtest: testing page read speed
[ 58.410431] mtd_speedtest: page read speed is 7796 KiB/s
[ 58.636805] mtd_speedtest: testing 2 page write speed
[ 61.612427] mtd_speedtest: 2 page write speed is 2757 KiB/s
[ 61.618021] mtd_speedtest: testing 2 page read speed
[ 62.672653] mtd_speedtest: 2 page read speed is 7804 KiB/s
[ 62.678159] mtd_speedtest: Testing erase speed
[ 62.903617] mtd_speedtest: erase speed is 37063 KiB/s
[ 62.908678] mtd_speedtest: Testing 2x multi-block erase speed
[ 63.134083] mtd_speedtest: 2x multi-block erase speed is 37292 KiB/s
[ 63.140442] mtd_speedtest: Testing 4x multi-block erase speed
[ 63.364262] mtd_speedtest: 4x multi-block erase speed is 37566 KiB/s
[ 63.370632] mtd_speedtest: Testing 8x multi-block erase speed
[ 63.595740] mtd_speedtest: 8x multi-block erase speed is 37344 KiB/s
[ 63.602089] mtd_speedtest: Testing 16x multi-block erase speed
[ 63.827426] mtd_speedtest: 16x multi-block erase speed is 37320 KiB/s
[ 63.833860] mtd_speedtest: Testing 32x multi-block erase speed
[ 64.059389] mtd_speedtest: 32x multi-block erase speed is 37288 KiB/s
[ 64.065833] mtd_speedtest: Testing 64x multi-block erase speed
[ 64.290609] mtd_speedtest: 64x multi-block erase speed is 37415 KiB/s
[ 64.297063] mtd_speedtest: finished
[ 64.300555] =================================================
Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240922-airoha-spi-fixes-v3-1-f958802b3d68@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-airoha-snfi.c | 154 ++++++++++++++++------------------
1 file changed, 71 insertions(+), 83 deletions(-)
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -206,13 +206,6 @@ enum airoha_snand_cs {
SPI_CHIP_SEL_LOW,
};
-struct airoha_snand_dev {
- size_t buf_len;
-
- u8 *txrx_buf;
- dma_addr_t dma_addr;
-};
-
struct airoha_snand_ctrl {
struct device *dev;
struct regmap *regmap_ctrl;
@@ -617,9 +610,9 @@ static bool airoha_snand_supports_op(str
static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct airoha_snand_dev *as_dev = spi_get_ctldata(desc->mem->spi);
+ u8 *txrx_buf = spi_get_ctldata(desc->mem->spi);
- if (!as_dev->txrx_buf)
+ if (!txrx_buf)
return -EINVAL;
if (desc->info.offset + desc->info.length > U32_MAX)
@@ -634,10 +627,11 @@ static int airoha_snand_dirmap_create(st
static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
- struct spi_device *spi = desc->mem->spi;
- struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
struct spi_mem_op *op = &desc->info.op_tmpl;
+ struct spi_device *spi = desc->mem->spi;
struct airoha_snand_ctrl *as_ctrl;
+ u8 *txrx_buf = spi_get_ctldata(spi);
+ dma_addr_t dma_addr;
u32 val, rd_mode;
int err;
@@ -662,14 +656,17 @@ static ssize_t airoha_snand_dirmap_read(
if (err)
return err;
- dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
+ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
+ err = dma_mapping_error(as_ctrl->dev, dma_addr);
+ if (err)
+ return err;
/* set dma addr */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
- as_dev->dma_addr);
+ dma_addr);
if (err)
- return err;
+ goto error_dma_unmap;
/* set cust sec size */
val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num;
@@ -678,58 +675,58 @@ static ssize_t airoha_snand_dirmap_read(
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_READ_DATA_BYTE_NUM, val);
if (err)
- return err;
+ goto error_dma_unmap;
/* set read command */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2,
op->cmd.opcode);
if (err)
- return err;
+ goto error_dma_unmap;
/* set read mode */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode));
if (err)
- return err;
+ goto error_dma_unmap;
/* set read addr */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0);
if (err)
- return err;
+ goto error_dma_unmap;
/* set nfi read */
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_OPMODE,
FIELD_PREP(SPI_NFI_OPMODE, 6));
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0);
if (err)
- return err;
+ goto error_dma_unmap;
/* trigger dma start read */
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_RD_TRIG);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_RD_TRIG);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_STA_CTL1, val,
(val & SPI_NFI_READ_FROM_CACHE_DONE),
0, 1 * USEC_PER_SEC);
if (err)
- return err;
+ goto error_dma_unmap;
/*
* SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
@@ -739,35 +736,41 @@ static ssize_t airoha_snand_dirmap_read(
SPI_NFI_READ_FROM_CACHE_DONE,
SPI_NFI_READ_FROM_CACHE_DONE);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
val, (val & SPI_NFI_AHB_DONE), 0,
1 * USEC_PER_SEC);
if (err)
- return err;
+ goto error_dma_unmap;
/* DMA read need delay for data ready from controller to DRAM */
udelay(1);
- dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
if (err < 0)
return err;
- memcpy(buf, as_dev->txrx_buf + offs, len);
+ memcpy(buf, txrx_buf + offs, len);
return len;
+
+error_dma_unmap:
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
+ return err;
}
static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, const void *buf)
{
- struct spi_device *spi = desc->mem->spi;
- struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
struct spi_mem_op *op = &desc->info.op_tmpl;
+ struct spi_device *spi = desc->mem->spi;
+ u8 *txrx_buf = spi_get_ctldata(spi);
struct airoha_snand_ctrl *as_ctrl;
+ dma_addr_t dma_addr;
u32 wr_mode, val;
int err;
@@ -776,19 +779,20 @@ static ssize_t airoha_snand_dirmap_write
if (err < 0)
return err;
- dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
- memcpy(as_dev->txrx_buf + offs, buf, len);
- dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
+ memcpy(txrx_buf + offs, buf, len);
+ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+ err = dma_mapping_error(as_ctrl->dev, dma_addr);
+ if (err)
+ return err;
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
if (err < 0)
- return err;
+ goto error_dma_unmap;
err = airoha_snand_nfi_config(as_ctrl);
if (err)
- return err;
+ goto error_dma_unmap;
if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD ||
op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD)
@@ -797,9 +801,9 @@ static ssize_t airoha_snand_dirmap_write
wr_mode = 0;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
- as_dev->dma_addr);
+ dma_addr);
if (err)
- return err;
+ goto error_dma_unmap;
val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM,
as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num);
@@ -807,65 +811,65 @@ static ssize_t airoha_snand_dirmap_write
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_PROG_LOAD_BYTE_NUM, val);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1,
FIELD_PREP(SPI_NFI_PG_LOAD_CMD,
op->cmd.opcode));
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode));
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_READ_MODE);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_OPMODE,
FIELD_PREP(SPI_NFI_OPMODE, 3));
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_DMA_MODE);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_WR_TRIG);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_WR_TRIG);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
val, (val & SPI_NFI_AHB_DONE), 0,
1 * USEC_PER_SEC);
if (err)
- return err;
+ goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_STA_CTL1, val,
(val & SPI_NFI_LOAD_TO_CACHE_DONE),
0, 1 * USEC_PER_SEC);
if (err)
- return err;
+ goto error_dma_unmap;
/*
* SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
@@ -875,13 +879,20 @@ static ssize_t airoha_snand_dirmap_write
SPI_NFI_LOAD_TO_CACHE_DONE,
SPI_NFI_LOAD_TO_CACHE_DONE);
if (err)
- return err;
+ goto error_dma_unmap;
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
if (err < 0)
return err;
return len;
+
+error_dma_unmap:
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+ return err;
}
static int airoha_snand_exec_op(struct spi_mem *mem,
@@ -956,42 +967,20 @@ static const struct spi_controller_mem_o
static int airoha_snand_setup(struct spi_device *spi)
{
struct airoha_snand_ctrl *as_ctrl;
- struct airoha_snand_dev *as_dev;
-
- as_ctrl = spi_controller_get_devdata(spi->controller);
-
- as_dev = devm_kzalloc(as_ctrl->dev, sizeof(*as_dev), GFP_KERNEL);
- if (!as_dev)
- return -ENOMEM;
+ u8 *txrx_buf;
/* prepare device buffer */
- as_dev->buf_len = SPI_NAND_CACHE_SIZE;
- as_dev->txrx_buf = devm_kzalloc(as_ctrl->dev, as_dev->buf_len,
- GFP_KERNEL);
- if (!as_dev->txrx_buf)
- return -ENOMEM;
-
- as_dev->dma_addr = dma_map_single(as_ctrl->dev, as_dev->txrx_buf,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr))
+ as_ctrl = spi_controller_get_devdata(spi->controller);
+ txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE,
+ GFP_KERNEL);
+ if (!txrx_buf)
return -ENOMEM;
- spi_set_ctldata(spi, as_dev);
+ spi_set_ctldata(spi, txrx_buf);
return 0;
}
-static void airoha_snand_cleanup(struct spi_device *spi)
-{
- struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
- struct airoha_snand_ctrl *as_ctrl;
-
- as_ctrl = spi_controller_get_devdata(spi->controller);
- dma_unmap_single(as_ctrl->dev, as_dev->dma_addr,
- as_dev->buf_len, DMA_BIDIRECTIONAL);
- spi_set_ctldata(spi, NULL);
-}
-
static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl)
{
u32 val, sec_size, sec_num;
@@ -1093,7 +1082,6 @@ static int airoha_snand_probe(struct pla
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->mode_bits = SPI_RX_DUAL;
ctrl->setup = airoha_snand_setup;
- ctrl->cleanup = airoha_snand_cleanup;
device_set_node(&ctrl->dev, dev_fwnode(dev));
err = airoha_snand_nfi_setup(as_ctrl);

View File

@ -0,0 +1,184 @@
From 2b0229f67932e4b9e2f458bf286903582bd30740 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 1 Aug 2024 09:35:12 +0200
Subject: [PATCH] net: dsa: mt7530: Add EN7581 support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce support for the DSA built-in switch available on the EN7581
development board. EN7581 support is similar to MT7988 one except
it requires to set MT7530_FORCE_MODE bit in MT753X_PMCR_P register
for on cpu port.
Tested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Arınç ÜNAL <arinc.unal@arinc9.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mt7530-mmio.c | 1 +
drivers/net/dsa/mt7530.c | 49 ++++++++++++++++++++++++++++++-----
drivers/net/dsa/mt7530.h | 20 ++++++++++----
3 files changed, 59 insertions(+), 11 deletions(-)
--- a/drivers/net/dsa/mt7530-mmio.c
+++ b/drivers/net/dsa/mt7530-mmio.c
@@ -11,6 +11,7 @@
#include "mt7530.h"
static const struct of_device_id mt7988_of_match[] = {
+ { .compatible = "airoha,en7581-switch", .data = &mt753x_table[ID_EN7581], },
{ .compatible = "mediatek,mt7988-switch", .data = &mt753x_table[ID_MT7988], },
{ /* sentinel */ },
};
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1152,7 +1152,8 @@ mt753x_cpu_port_enable(struct dsa_switch
* the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
* is affine to the inbound user port.
*/
- if (priv->id == ID_MT7531 || priv->id == ID_MT7988)
+ if (priv->id == ID_MT7531 || priv->id == ID_MT7988 ||
+ priv->id == ID_EN7581)
mt7530_set(priv, MT7531_CFC, MT7531_CPU_PMAP(BIT(port)));
/* CPU port gets connected to all user ports of
@@ -2207,7 +2208,7 @@ mt7530_setup_irq(struct mt7530_priv *pri
return priv->irq ? : -EINVAL;
}
- if (priv->id == ID_MT7988)
+ if (priv->id == ID_MT7988 || priv->id == ID_EN7581)
priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
&mt7988_irq_domain_ops,
priv);
@@ -2438,8 +2439,10 @@ mt7530_setup(struct dsa_switch *ds)
/* Clear link settings and enable force mode to force link down
* on all ports until they're enabled later.
*/
- mt7530_rmw(priv, MT753X_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
- MT7530_FORCE_MODE, MT7530_FORCE_MODE);
+ mt7530_rmw(priv, MT753X_PMCR_P(i),
+ PMCR_LINK_SETTINGS_MASK |
+ MT753X_FORCE_MODE(priv->id),
+ MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
@@ -2550,8 +2553,10 @@ mt7531_setup_common(struct dsa_switch *d
/* Clear link settings and enable force mode to force link down
* on all ports until they're enabled later.
*/
- mt7530_rmw(priv, MT753X_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
- MT7531_FORCE_MODE_MASK, MT7531_FORCE_MODE_MASK);
+ mt7530_rmw(priv, MT753X_PMCR_P(i),
+ PMCR_LINK_SETTINGS_MASK |
+ MT753X_FORCE_MODE(priv->id),
+ MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
@@ -2783,6 +2788,28 @@ static void mt7988_mac_port_get_caps(str
}
}
+static void en7581_mac_port_get_caps(struct dsa_switch *ds, int port,
+ struct phylink_config *config)
+{
+ switch (port) {
+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
+ case 0 ... 4:
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+
+ config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000FD;
+ break;
+
+ /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */
+ case 6:
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+
+ config->mac_capabilities |= MAC_10000FD;
+ break;
+ }
+}
+
static void
mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface)
@@ -3220,6 +3247,16 @@ const struct mt753x_info mt753x_table[]
.phy_write_c45 = mt7531_ind_c45_phy_write,
.mac_port_get_caps = mt7988_mac_port_get_caps,
},
+ [ID_EN7581] = {
+ .id = ID_EN7581,
+ .pcs_ops = &mt7530_pcs_ops,
+ .sw_setup = mt7988_setup,
+ .phy_read_c22 = mt7531_ind_c22_phy_read,
+ .phy_write_c22 = mt7531_ind_c22_phy_write,
+ .phy_read_c45 = mt7531_ind_c45_phy_read,
+ .phy_write_c45 = mt7531_ind_c45_phy_write,
+ .mac_port_get_caps = en7581_mac_port_get_caps,
+ },
};
EXPORT_SYMBOL_GPL(mt753x_table);
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -19,6 +19,7 @@ enum mt753x_id {
ID_MT7621 = 1,
ID_MT7531 = 2,
ID_MT7988 = 3,
+ ID_EN7581 = 4,
};
#define NUM_TRGMII_CTRL 5
@@ -64,25 +65,30 @@ enum mt753x_id {
#define MT7531_CPU_PMAP(x) FIELD_PREP(MT7531_CPU_PMAP_MASK, x)
#define MT753X_MIRROR_REG(id) ((id == ID_MT7531 || \
- id == ID_MT7988) ? \
+ id == ID_MT7988 || \
+ id == ID_EN7581) ? \
MT7531_CFC : MT753X_MFC)
#define MT753X_MIRROR_EN(id) ((id == ID_MT7531 || \
- id == ID_MT7988) ? \
+ id == ID_MT7988 || \
+ id == ID_EN7581) ? \
MT7531_MIRROR_EN : MT7530_MIRROR_EN)
#define MT753X_MIRROR_PORT_MASK(id) ((id == ID_MT7531 || \
- id == ID_MT7988) ? \
+ id == ID_MT7988 || \
+ id == ID_EN7581) ? \
MT7531_MIRROR_PORT_MASK : \
MT7530_MIRROR_PORT_MASK)
#define MT753X_MIRROR_PORT_GET(id, val) ((id == ID_MT7531 || \
- id == ID_MT7988) ? \
+ id == ID_MT7988 || \
+ id == ID_EN7581) ? \
MT7531_MIRROR_PORT_GET(val) : \
MT7530_MIRROR_PORT_GET(val))
#define MT753X_MIRROR_PORT_SET(id, val) ((id == ID_MT7531 || \
- id == ID_MT7988) ? \
+ id == ID_MT7988 || \
+ id == ID_EN7581) ? \
MT7531_MIRROR_PORT_SET(val) : \
MT7530_MIRROR_PORT_SET(val))
@@ -355,6 +361,10 @@ enum mt7530_vlan_port_acc_frm {
MT7531_FORCE_MODE_TX_FC | \
MT7531_FORCE_MODE_EEE100 | \
MT7531_FORCE_MODE_EEE1G)
+#define MT753X_FORCE_MODE(id) ((id == ID_MT7531 || \
+ id == ID_MT7988) ? \
+ MT7531_FORCE_MODE_MASK : \
+ MT7530_FORCE_MODE)
#define PMCR_LINK_SETTINGS_MASK (PMCR_MAC_TX_EN | PMCR_MAC_RX_EN | \
PMCR_FORCE_EEE1G | \
PMCR_FORCE_EEE100 | \

View File

@ -0,0 +1,247 @@
From 5296da64f77ef6c809b715cdecf308977a08acb9 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 16 Oct 2024 18:00:57 +0200
Subject: [PATCH] cpufreq: airoha: Add EN7581 Cpufreq SMC driver
Add simple Cpufreq driver for Airoha EN7581 SoC that control CPU
frequency scaling with SMC APIs.
All CPU share the same frequency and can't be controlled independently.
Current shared CPU frequency is returned by the related SMC command.
Add SoC compatible to cpufreq-dt-plat block list as a dedicated cpufreq
driver is needed with OPP v2 nodes declared in DTS.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/cpufreq/Kconfig.arm | 8 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/airoha-cpufreq.c | 183 +++++++++++++++++++++++++++
drivers/cpufreq/cpufreq-dt-platdev.c | 2 +
4 files changed, 194 insertions(+)
create mode 100644 drivers/cpufreq/airoha-cpufreq.c
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -41,6 +41,14 @@ config ARM_ALLWINNER_SUN50I_CPUFREQ_NVME
To compile this driver as a module, choose M here: the
module will be called sun50i-cpufreq-nvmem.
+config ARM_AIROHA_SOC_CPUFREQ
+ tristate "Airoha EN7581 SoC CPUFreq support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ select PM_OPP
+ default ARCH_AIROHA
+ help
+ This adds the CPUFreq driver for Airoha EN7581 SoCs.
+
config ARM_APPLE_SOC_CPUFREQ
tristate "Apple Silicon SoC CPUFreq support"
depends on ARCH_APPLE || (COMPILE_TEST && 64BIT)
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) +
##################################################################################
# ARM SoC drivers
+obj-$(CONFIG_ARM_AIROHA_SOC_CPUFREQ) += airoha-cpufreq.o
obj-$(CONFIG_ARM_APPLE_SOC_CPUFREQ) += apple-soc-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ) += armada-8k-cpufreq.o
--- /dev/null
+++ b/drivers/cpufreq/airoha-cpufreq.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/arm-smccc.h>
+
+#define AIROHA_SIP_AVS_HANDLE 0x82000301
+#define AIROHA_AVS_OP_BASE 0xddddddd0
+#define AIROHA_AVS_OP_MASK GENMASK(1, 0)
+#define AIROHA_AVS_OP_FREQ_DYN_ADJ (AIROHA_AVS_OP_BASE | \
+ FIELD_PREP(AIROHA_AVS_OP_MASK, 0x1))
+#define AIROHA_AVS_OP_GET_FREQ (AIROHA_AVS_OP_BASE | \
+ FIELD_PREP(AIROHA_AVS_OP_MASK, 0x2))
+
+struct airoha_cpufreq_priv {
+ struct list_head list;
+
+ cpumask_var_t cpus;
+ struct device *cpu_dev;
+ struct cpufreq_frequency_table *freq_table;
+};
+
+static LIST_HEAD(priv_list);
+
+static unsigned int airoha_cpufreq_get(unsigned int cpu)
+{
+ const struct arm_smccc_1_2_regs args = {
+ .a0 = AIROHA_SIP_AVS_HANDLE,
+ .a1 = AIROHA_AVS_OP_GET_FREQ,
+ };
+ struct arm_smccc_1_2_regs res;
+
+ arm_smccc_1_2_smc(&args, &res);
+
+ return (int)(res.a0 * 1000);
+}
+
+static int airoha_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ const struct arm_smccc_1_2_regs args = {
+ .a0 = AIROHA_SIP_AVS_HANDLE,
+ .a1 = AIROHA_AVS_OP_FREQ_DYN_ADJ,
+ .a3 = index,
+ };
+ struct arm_smccc_1_2_regs res;
+
+ arm_smccc_1_2_smc(&args, &res);
+
+ /* SMC signal correct apply by unsetting BIT 0 */
+ return res.a0 & BIT(0) ? -EINVAL : 0;
+}
+
+static struct airoha_cpufreq_priv *airoha_cpufreq_find_data(int cpu)
+{
+ struct airoha_cpufreq_priv *priv;
+
+ list_for_each_entry(priv, &priv_list, list) {
+ if (cpumask_test_cpu(cpu, priv->cpus))
+ return priv;
+ }
+
+ return NULL;
+}
+
+static int airoha_cpufreq_init(struct cpufreq_policy *policy)
+{
+ struct airoha_cpufreq_priv *priv;
+ struct device *cpu_dev;
+
+ priv = airoha_cpufreq_find_data(policy->cpu);
+ if (!priv)
+ return -ENODEV;
+
+ cpu_dev = priv->cpu_dev;
+ cpumask_copy(policy->cpus, priv->cpus);
+ policy->driver_data = priv;
+ policy->freq_table = priv->freq_table;
+
+ return 0;
+}
+
+static struct cpufreq_driver airoha_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+ CPUFREQ_IS_COOLING_DEV,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = airoha_cpufreq_set_target,
+ .get = airoha_cpufreq_get,
+ .init = airoha_cpufreq_init,
+ .attr = cpufreq_generic_attr,
+ .name = "airoha-cpufreq",
+};
+
+static int airoha_cpufreq_driver_init_cpu(int cpu)
+{
+ struct airoha_cpufreq_priv *priv;
+ struct device *cpu_dev;
+ int ret;
+
+ cpu_dev = get_cpu_device(cpu);
+ if (!cpu_dev)
+ return -EPROBE_DEFER;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (!zalloc_cpumask_var(&priv->cpus, GFP_KERNEL))
+ return -ENOMEM;
+
+ cpumask_set_cpu(cpu, priv->cpus);
+ priv->cpu_dev = cpu_dev;
+
+ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->cpus);
+ if (ret)
+ goto err;
+
+ ret = dev_pm_opp_of_cpumask_add_table(priv->cpus);
+ if (ret)
+ goto err;
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &priv->freq_table);
+ if (ret)
+ goto err;
+
+ list_add(&priv->list, &priv_list);
+
+ return 0;
+
+err:
+ dev_pm_opp_of_cpumask_remove_table(priv->cpus);
+ free_cpumask_var(priv->cpus);
+
+ return ret;
+}
+
+static void airoha_cpufreq_release(void)
+{
+ struct airoha_cpufreq_priv *priv, *tmp;
+
+ list_for_each_entry_safe(priv, tmp, &priv_list, list) {
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
+ dev_pm_opp_of_cpumask_remove_table(priv->cpus);
+ free_cpumask_var(priv->cpus);
+ list_del(&priv->list);
+ kfree(priv);
+ }
+}
+
+static int __init airoha_cpufreq_driver_probe(void)
+{
+ int cpu, ret;
+
+ if (!of_machine_is_compatible("airoha,en7581"))
+ return -ENODEV;
+
+ for_each_possible_cpu(cpu) {
+ ret = airoha_cpufreq_driver_init_cpu(cpu);
+ if (ret)
+ goto err;
+ }
+
+ ret = cpufreq_register_driver(&airoha_cpufreq_driver);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ airoha_cpufreq_release();
+ return ret;
+}
+module_init(airoha_cpufreq_driver_probe);
+
+static void __exit airoha_cpufreq_driver_remove(void)
+{
+ cpufreq_unregister_driver(&airoha_cpufreq_driver);
+ airoha_cpufreq_release();
+}
+module_exit(airoha_cpufreq_driver_remove);
+
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("CPUfreq driver for Airoha SoCs");
+MODULE_LICENSE("GPL");
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -103,6 +103,8 @@ static const struct of_device_id allowli
* platforms using "operating-points-v2" property.
*/
static const struct of_device_id blocklist[] __initconst = {
+ { .compatible = "airoha,en7581", },
+
{ .compatible = "allwinner,sun50i-h6", },
{ .compatible = "apple,arm-platform", },

View File

@ -0,0 +1,210 @@
From 1f194995c3648e20da53137d4c9110b39e779f41 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Fri, 18 Oct 2024 11:34:35 +0200
Subject: [PATCH 2/3] thermal: of: Add
devm_thermal_of_zone_register_with_params() variant
Commit b1ae92dcfa8e ("thermal: core: Make struct thermal_zone_device
definition internal") moved the thermal_zone_device struct from global
thermal.h to internal thermal_core.h making the internal variables of
the struct not accessible from the user drivers (without inclusing
thermal_core.h).
One case where the internal variables might be needed is for the
thermal_zone_params in the context of OF probe.
In such case a thermal driver might have default params that can only be
parsed at runtime (example present in EFUSE or derived from other values)
and wants to update the values in the thermal_zone_params for the
thermal device. (to use the helper like get_slope() or get_offset())
To account for this scenario, introduce a variant of
devm_thermal_of_zone_register(),
devm_thermal_of_zone_register_with_params(), that takes and additional
variable and permits to register the thermal device with default
thermal_zone_params.
To follow OF implementation, these params are only treated as default
params and are ignored if a related one is defined in DT. (example a
slope or offset value defined in DT have priority to the default one
passed in a thermal_device_params struct)
This permits to support both implementation, use the helpers and expose
these values in sysfs.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/thermal/thermal_of.c | 67 +++++++++++++++++++++++++++++-------
include/linux/thermal.h | 13 +++++++
2 files changed, 68 insertions(+), 12 deletions(-)
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -249,7 +249,7 @@ static void thermal_of_parameters_init(s
{
int coef[2];
int ncoef = ARRAY_SIZE(coef);
- int prop, ret;
+ int prop;
tzp->no_hwmon = true;
@@ -261,14 +261,11 @@ static void thermal_of_parameters_init(s
* thermal zone. Thus, we are considering only the first two
* values as slope and offset.
*/
- ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
- if (ret) {
- coef[0] = 1;
- coef[1] = 0;
+ if (!of_property_read_u32_array(np, "coefficients", coef, ncoef)) {
+ tzp->slope = coef[0];
+ tzp->offset = coef[1];
}
- tzp->slope = coef[0];
- tzp->offset = coef[1];
}
static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
@@ -462,10 +459,15 @@ static void thermal_of_zone_unregister(s
* zone properties and registers new thermal zone with those
* properties.
*
+ * The passed thermal zone params are treated as default values and ignored if
+ * the related property is found in DT. (DT params have priority to
+ * default values)
+ *
* @sensor: A device node pointer corresponding to the sensor in the device tree
* @id: An integer as sensor identifier
* @data: A private data to be stored in the thermal zone dedicated private area
* @ops: A set of thermal sensor ops
+ * @tzp: a pointer to the default thermal zone params structure associated with the sensor
*
* Return: a valid thermal zone structure pointer on success.
* - EINVAL: if the device tree thermal description is malformed
@@ -473,11 +475,11 @@ static void thermal_of_zone_unregister(s
* - Other negative errors are returned by the underlying called functions
*/
static struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data,
- const struct thermal_zone_device_ops *ops)
+ const struct thermal_zone_device_ops *ops,
+ struct thermal_zone_params *tzp)
{
struct thermal_zone_device *tz;
struct thermal_trip *trips;
- struct thermal_zone_params tzp = {};
struct thermal_zone_device_ops *of_ops;
struct device_node *np;
int delay, pdelay;
@@ -509,7 +511,7 @@ static struct thermal_zone_device *therm
goto out_kfree_trips;
}
- thermal_of_parameters_init(np, &tzp);
+ thermal_of_parameters_init(np, tzp);
of_ops->bind = thermal_of_bind;
of_ops->unbind = thermal_of_unbind;
@@ -517,7 +519,7 @@ static struct thermal_zone_device *therm
mask = GENMASK_ULL((ntrips) - 1, 0);
tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
- mask, data, of_ops, &tzp,
+ mask, data, of_ops, tzp,
pdelay, delay);
if (IS_ERR(tz)) {
ret = PTR_ERR(tz);
@@ -572,6 +574,7 @@ static int devm_thermal_of_zone_match(st
struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int sensor_id, void *data,
const struct thermal_zone_device_ops *ops)
{
+ struct thermal_zone_params tzp = { .slope = 1 };
struct thermal_zone_device **ptr, *tzd;
ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
@@ -579,7 +582,7 @@ struct thermal_zone_device *devm_thermal
if (!ptr)
return ERR_PTR(-ENOMEM);
- tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops);
+ tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops, &tzp);
if (IS_ERR(tzd)) {
devres_free(ptr);
return tzd;
@@ -593,6 +596,46 @@ struct thermal_zone_device *devm_thermal
EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
/**
+ * devm_thermal_of_zone_register_with_params - register a thermal tied with the sensor life cycle
+ * with default params
+ *
+ * This function is the device version of the thermal_of_zone_register() function.
+ *
+ * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
+ * @sensor_id: the sensor identifier
+ * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
+ * @ops: a pointer to the ops structure associated with the sensor
+ * @tzp: a pointer to the default thermal zone params structure associated with the sensor
+ *
+ * The thermal zone params are treated as default values and ignored if the related property is
+ * found in DT. (DT params have priority to default values)
+ */
+struct thermal_zone_device *devm_thermal_of_zone_register_with_params(struct device *dev, int sensor_id,
+ void *data,
+ const struct thermal_zone_device_ops *ops,
+ struct thermal_zone_params *tzp)
+{
+ struct thermal_zone_device **ptr, *tzd;
+
+ ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops, tzp);
+ if (IS_ERR(tzd)) {
+ devres_free(ptr);
+ return tzd;
+ }
+
+ *ptr = tzd;
+ devres_add(dev, ptr);
+
+ return tzd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register_with_params);
+
+/**
* devm_thermal_of_zone_unregister - Resource managed version of
* thermal_of_zone_unregister().
* @dev: Device for which which resource was allocated.
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -261,6 +261,10 @@ struct thermal_zone_params {
#ifdef CONFIG_THERMAL_OF
struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int id, void *data,
const struct thermal_zone_device_ops *ops);
+struct thermal_zone_device *devm_thermal_of_zone_register_with_params(struct device *dev, int id,
+ void *data,
+ const struct thermal_zone_device_ops *ops,
+ struct thermal_zone_params *tzp);
void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz);
@@ -272,6 +276,15 @@ struct thermal_zone_device *devm_thermal
{
return ERR_PTR(-ENOTSUPP);
}
+
+static inline
+struct thermal_zone_device *devm_thermal_of_zone_register_with_params(struct device *dev, int id,
+ void *data,
+ const struct thermal_zone_device_ops *ops,
+ struct thermal_zone_params *tzp)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
static inline void devm_thermal_of_zone_unregister(struct device *dev,
struct thermal_zone_device *tz)

View File

@ -0,0 +1,535 @@
From bc6a6a4ec6c28467683121cc165e5681b4acdf8d Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 27 Aug 2024 23:04:53 +0200
Subject: [PATCH 3/3] thermal: Add support for Airoha EN7581 thermal sensor
Add support for Airoha EN7581 thermal sensor. This provide support for
reading the CPU or SoC Package sensor and to setup trip points for hot
and critical condition. An interrupt is fired to react on this and
doesn't require passive poll to read the temperature.
The thermal regs provide a way to read the ADC value from an external
register placed in the Chip SCU regs. Monitor will read this value and
fire an interrupt if the trip condition configured is reached.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/thermal/Kconfig | 9 +
drivers/thermal/Makefile | 1 +
drivers/thermal/airoha_thermal.c | 482 +++++++++++++++++++++++++++++++
3 files changed, 492 insertions(+)
create mode 100644 drivers/thermal/airoha_thermal.c
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -317,6 +317,15 @@ config QORIQ_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
+config AIROHA_THERMAL
+ tristate "Airoha thermal sensor driver"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on MFD_SYSCON
+ depends on OF
+ help
+ Enable this to plug the Airoha thermal sensor driver into the Linux
+ thermal framework.
+
config SPEAR_THERMAL
tristate "SPEAr thermal sensor driver"
depends on PLAT_SPEAR || COMPILE_TEST
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o
# platform thermal drivers
obj-y += broadcom/
obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o
+obj-$(CONFIG_AIROHA_THERMAL) += airoha_thermal.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
--- /dev/null
+++ b/drivers/thermal/airoha_thermal.c
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/module.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+
+/* SCU regs */
+#define EN7581_PLLRG_PROTECT 0x268
+#define EN7581_PWD_TADC 0x2ec
+#define EN7581_MUX_TADC GENMASK(3, 1)
+#define EN7581_DOUT_TADC 0x2f8
+#define EN7581_DOUT_TADC_MASK GENMASK(15, 0)
+
+/* PTP_THERMAL regs */
+#define EN7581_TEMPMONCTL0 0x800
+#define EN7581_SENSE3_EN BIT(3)
+#define EN7581_SENSE2_EN BIT(2)
+#define EN7581_SENSE1_EN BIT(1)
+#define EN7581_SENSE0_EN BIT(0)
+#define EN7581_TEMPMONCTL1 0x804
+/* period unit calculated in BUS clock * 256 scaling-up */
+#define EN7581_PERIOD_UNIT GENMASK(9, 0)
+#define EN7581_TEMPMONCTL2 0x808
+#define EN7581_FILT_INTERVAL GENMASK(25, 16)
+#define EN7581_SEN_INTERVAL GENMASK(9, 0)
+#define EN7581_TEMPMONINT 0x80C
+#define EN7581_STAGE3_INT_EN BIT(31)
+#define EN7581_STAGE2_INT_EN BIT(30)
+#define EN7581_STAGE1_INT_EN BIT(29)
+#define EN7581_FILTER_INT_EN_3 BIT(28)
+#define EN7581_IMMD_INT_EN3 BIT(27)
+#define EN7581_NOHOTINTEN3 BIT(26)
+#define EN7581_HOFSINTEN3 BIT(25)
+#define EN7581_LOFSINTEN3 BIT(24)
+#define EN7581_HINTEN3 BIT(23)
+#define EN7581_CINTEN3 BIT(22)
+#define EN7581_FILTER_INT_EN_2 BIT(21)
+#define EN7581_FILTER_INT_EN_1 BIT(20)
+#define EN7581_FILTER_INT_EN_0 BIT(19)
+#define EN7581_IMMD_INT_EN2 BIT(18)
+#define EN7581_IMMD_INT_EN1 BIT(17)
+#define EN7581_IMMD_INT_EN0 BIT(16)
+#define EN7581_TIME_OUT_INT_EN BIT(15)
+#define EN7581_NOHOTINTEN2 BIT(14)
+#define EN7581_HOFSINTEN2 BIT(13)
+#define EN7581_LOFSINTEN2 BIT(12)
+#define EN7581_HINTEN2 BIT(11)
+#define EN7581_CINTEN2 BIT(10)
+#define EN7581_NOHOTINTEN1 BIT(9)
+#define EN7581_HOFSINTEN1 BIT(8)
+#define EN7581_LOFSINTEN1 BIT(7)
+#define EN7581_HINTEN1 BIT(6)
+#define EN7581_CINTEN1 BIT(5)
+#define EN7581_NOHOTINTEN0 BIT(4)
+/* Similar to COLD and HOT also these seems to be swapped in documentation */
+#define EN7581_LOFSINTEN0 BIT(3) /* In documentation: BIT(2) */
+#define EN7581_HOFSINTEN0 BIT(2) /* In documentation: BIT(3) */
+/* It seems documentation have these swapped as the HW
+ * - Fire BIT(1) when lower than EN7581_COLD_THRE
+ * - Fire BIT(0) and BIT(5) when higher than EN7581_HOT2NORMAL_THRE or
+ * EN7581_HOT_THRE
+ */
+#define EN7581_CINTEN0 BIT(1) /* In documentation: BIT(0) */
+#define EN7581_HINTEN0 BIT(0) /* In documentation: BIT(1) */
+#define EN7581_TEMPMONINTSTS 0x810
+#define EN7581_STAGE3_INT_STAT BIT(31)
+#define EN7581_STAGE2_INT_STAT BIT(30)
+#define EN7581_STAGE1_INT_STAT BIT(29)
+#define EN7581_FILTER_INT_STAT_3 BIT(28)
+#define EN7581_IMMD_INT_STS3 BIT(27)
+#define EN7581_NOHOTINTSTS3 BIT(26)
+#define EN7581_HOFSINTSTS3 BIT(25)
+#define EN7581_LOFSINTSTS3 BIT(24)
+#define EN7581_HINTSTS3 BIT(23)
+#define EN7581_CINTSTS3 BIT(22)
+#define EN7581_FILTER_INT_STAT_2 BIT(21)
+#define EN7581_FILTER_INT_STAT_1 BIT(20)
+#define EN7581_FILTER_INT_STAT_0 BIT(19)
+#define EN7581_IMMD_INT_STS2 BIT(18)
+#define EN7581_IMMD_INT_STS1 BIT(17)
+#define EN7581_IMMD_INT_STS0 BIT(16)
+#define EN7581_TIME_OUT_INT_STAT BIT(15)
+#define EN7581_NOHOTINTSTS2 BIT(14)
+#define EN7581_HOFSINTSTS2 BIT(13)
+#define EN7581_LOFSINTSTS2 BIT(12)
+#define EN7581_HINTSTS2 BIT(11)
+#define EN7581_CINTSTS2 BIT(10)
+#define EN7581_NOHOTINTSTS1 BIT(9)
+#define EN7581_HOFSINTSTS1 BIT(8)
+#define EN7581_LOFSINTSTS1 BIT(7)
+#define EN7581_HINTSTS1 BIT(6)
+#define EN7581_CINTSTS1 BIT(5)
+#define EN7581_NOHOTINTSTS0 BIT(4)
+/* Similar to COLD and HOT also these seems to be swapped in documentation */
+#define EN7581_LOFSINTSTS0 BIT(3) /* In documentation: BIT(2) */
+#define EN7581_HOFSINTSTS0 BIT(2) /* In documentation: BIT(3) */
+/* It seems documentation have these swapped as the HW
+ * - Fire BIT(1) when lower than EN7581_COLD_THRE
+ * - Fire BIT(0) and BIT(5) when higher than EN7581_HOT2NORMAL_THRE or
+ * EN7581_HOT_THRE
+ *
+ * To clear things, we swap the define but we keep them documented here.
+ */
+#define EN7581_CINTSTS0 BIT(1) /* In documentation: BIT(0) */
+#define EN7581_HINTSTS0 BIT(0) /* In documentation: BIT(1)*/
+/* Monitor will take the bigger threshold between HOT2NORMAL and HOT
+ * and will fire both HOT2NORMAL and HOT interrupt when higher than the 2
+ *
+ * It has also been observed that not setting HOT2NORMAL makes the monitor
+ * treat COLD threshold as HOT2NORMAL.
+ */
+#define EN7581_TEMPH2NTHRE 0x824
+/* It seems HOT2NORMAL is actually NORMAL2HOT */
+#define EN7581_HOT2NORMAL_THRE GENMASK(11, 0)
+#define EN7581_TEMPHTHRE 0x828
+#define EN7581_HOT_THRE GENMASK(11, 0)
+/* Monitor will use this as HOT2NORMAL (fire interrupt when lower than...)*/
+#define EN7581_TEMPCTHRE 0x82c
+#define EN7581_COLD_THRE GENMASK(11, 0)
+/* Also LOW and HIGH offset register are swapped */
+#define EN7581_TEMPOFFSETL 0x830 /* In documentation: 0x834 */
+#define EN7581_LOW_OFFSET GENMASK(11, 0)
+#define EN7581_TEMPOFFSETH 0x834 /* In documentation: 0x830 */
+#define EN7581_HIGH_OFFSET GENMASK(11, 0)
+#define EN7581_TEMPMSRCTL0 0x838
+#define EN7581_MSRCTL3 GENMASK(11, 9)
+#define EN7581_MSRCTL2 GENMASK(8, 6)
+#define EN7581_MSRCTL1 GENMASK(5, 3)
+#define EN7581_MSRCTL0 GENMASK(2, 0)
+#define EN7581_TEMPADCVALIDADDR 0x878
+#define EN7581_ADC_VALID_ADDR GENMASK(31, 0)
+#define EN7581_TEMPADCVOLTADDR 0x87c
+#define EN7581_ADC_VOLT_ADDR GENMASK(31, 0)
+#define EN7581_TEMPRDCTRL 0x880
+/*
+ * NOTICE: AHB have this set to 0 by default. Means that
+ * the same addr is used for ADC volt and valid reading.
+ * In such case, VALID ADDR is used and volt addr is ignored.
+ */
+#define EN7581_RD_CTRL_DIFF BIT(0)
+#define EN7581_TEMPADCVALIDMASK 0x884
+#define EN7581_ADV_RD_VALID_POLARITY BIT(5)
+#define EN7581_ADV_RD_VALID_POS GENMASK(4, 0)
+#define EN7581_TEMPADCVOLTAGESHIFT 0x888
+#define EN7581_ADC_VOLTAGE_SHIFT GENMASK(4, 0)
+/*
+ * Same values for each CTL.
+ * Can operate in:
+ * - 1 sample
+ * - 2 sample and make average of them
+ * - 4,6,10,16 sample, drop max and min and make avgerage of them
+ */
+#define EN7581_MSRCTL_1SAMPLE 0x0
+#define EN7581_MSRCTL_AVG2SAMPLE 0x1
+#define EN7581_MSRCTL_4SAMPLE_MAX_MIX_AVG2 0x2
+#define EN7581_MSRCTL_6SAMPLE_MAX_MIX_AVG4 0x3
+#define EN7581_MSRCTL_10SAMPLE_MAX_MIX_AVG8 0x4
+#define EN7581_MSRCTL_18SAMPLE_MAX_MIX_AVG16 0x5
+#define EN7581_TEMPAHBPOLL 0x840
+#define EN7581_ADC_POLL_INTVL GENMASK(31, 0)
+/* PTPSPARE0,2 reg are used to store efuse info for calibrated temp offset */
+#define EN7581_EFUSE_TEMP_OFFSET_REG 0xf20 /* PTPSPARE0 */
+#define EN7581_EFUSE_TEMP_OFFSET GENMASK(31, 16)
+#define EN7581_PTPSPARE1 0xf24 /* PTPSPARE1 */
+#define EN7581_EFUSE_TEMP_CPU_SENSOR_REG 0xf28 /* PTPSPARE2 */
+
+#define EN7581_SLOPE_X100_DIO_DEFAULT 5645
+#define EN7581_SLOPE_X100_DIO_AVS 5645
+
+#define EN7581_INIT_TEMP_CPK_X10 300
+#define EN7581_INIT_TEMP_FTK_X10 620
+#define EN7581_INIT_TEMP_NONK_X10 550
+
+#define EN7581_SCU_THERMAL_PROTECT_KEY 0x12
+#define EN7581_SCU_THERMAL_MUX_DIODE1 0x7
+
+/* Convert temp to raw value as read from ADC ((((temp / 100) - init) * slope) / 1000) + offset */
+#define TEMP_TO_RAW(priv, tz, temp) ((((((temp) / 100) - (priv)->init_temp) * \
+ thermal_zone_get_slope(tz)) / 1000) + \
+ thermal_zone_get_offset(tz))
+
+/* Convert raw to temp ((((temp - offset) * 1000) / slope + init) * 100) */
+#define RAW_TO_TEMP(priv, tz, raw) (((((raw) - thermal_zone_get_offset(tz)) * 1000) / \
+ thermal_zone_get_slope(tz) + \
+ (priv)->init_temp) * 100)
+
+struct airoha_thermal_priv {
+ void __iomem *base;
+ struct regmap *chip_scu;
+ struct resource scu_adc_res;
+
+ struct thermal_zone_device *tz;
+ int init_temp;
+};
+
+static int airoha_get_thermal_ADC(struct airoha_thermal_priv *priv)
+{
+ u32 val;
+
+ regmap_read(priv->chip_scu, EN7581_DOUT_TADC, &val);
+ return FIELD_GET(EN7581_DOUT_TADC_MASK, val);
+}
+
+static void airoha_init_thermal_ADC_mode(struct airoha_thermal_priv *priv)
+{
+ u32 adc_mux, pllrg;
+
+ /* Save PLLRG current value */
+ regmap_read(priv->chip_scu, EN7581_PLLRG_PROTECT, &pllrg);
+
+ /* Give access to thermal regs */
+ regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, EN7581_SCU_THERMAL_PROTECT_KEY);
+ adc_mux = FIELD_PREP(EN7581_MUX_TADC, EN7581_SCU_THERMAL_MUX_DIODE1);
+ regmap_write(priv->chip_scu, EN7581_PWD_TADC, adc_mux);
+
+ /* Restore PLLRG value on exit */
+ regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, pllrg);
+}
+
+static int airoha_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+ struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
+ int min, max, avg_temp, temp_adc;
+ int i;
+
+ /* Get the starting temp */
+ temp_adc = airoha_get_thermal_ADC(priv);
+ min = temp_adc;
+ max = temp_adc;
+ avg_temp = temp_adc;
+
+ /* Make 5 more measurement and average the temp ADC difference */
+ for (i = 0; i < 5; i++) {
+ temp_adc = airoha_get_thermal_ADC(priv);
+ avg_temp += temp_adc;
+ if (temp_adc > max)
+ max = temp_adc;
+ if (temp_adc < min)
+ min = temp_adc;
+ }
+ avg_temp = avg_temp - max - min;
+ avg_temp /= 4;
+
+ *temp = RAW_TO_TEMP(priv, tz, avg_temp);
+ return 0;
+}
+
+static int airoha_thermal_set_trips(struct thermal_zone_device *tz, int low,
+ int high)
+{
+ struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
+
+ if (high != INT_MAX) {
+ /* Validate high and clamp them a sane value */
+ if (high > RAW_TO_TEMP(priv, tz, FIELD_MAX(EN7581_DOUT_TADC_MASK)))
+ high = 110000;
+
+ /* We offset the high temp of 1°C to trigger correct event */
+ writel(TEMP_TO_RAW(priv, tz, high) >> 4,
+ priv->base + EN7581_TEMPOFFSETH);
+ }
+
+ if (low != -INT_MAX) {
+ /* Validate low and clamp them to a sane value */
+ if (low < RAW_TO_TEMP(priv, tz, 0))
+ low = -33000;
+
+ /* We offset the low temp of 1°C to trigger correct event */
+ writel(TEMP_TO_RAW(priv, tz, low) >> 4,
+ priv->base + EN7581_TEMPOFFSETL);
+ }
+
+ /* Enable sensor 0 monitor */
+ writel(EN7581_SENSE0_EN, priv->base + EN7581_TEMPMONCTL0);
+
+ return 0;
+}
+
+static const struct thermal_zone_device_ops thdev_ops = {
+ .get_temp = airoha_thermal_get_temp,
+ .set_trips = airoha_thermal_set_trips,
+};
+
+static irqreturn_t airoha_thermal_irq(int irq, void *data)
+{
+ struct airoha_thermal_priv *priv = data;
+ enum thermal_notify_event event;
+ u32 status;
+
+ status = readl(priv->base + EN7581_TEMPMONINTSTS);
+ switch (status & (EN7581_HOFSINTSTS0 | EN7581_LOFSINTSTS0)) {
+ case EN7581_HOFSINTSTS0:
+ event = THERMAL_TRIP_VIOLATED;
+ break;
+ case EN7581_LOFSINTSTS0:
+ event = THERMAL_EVENT_UNSPECIFIED;
+ break;
+ default:
+ goto exit;
+ }
+
+ thermal_zone_device_update(priv->tz, event);
+
+exit:
+ /* reset interrupt */
+ writel(status, priv->base + EN7581_TEMPMONINTSTS);
+
+ return IRQ_HANDLED;
+}
+
+static void airoha_thermal_setup_adc_val(struct device *dev,
+ struct airoha_thermal_priv *priv,
+ struct thermal_zone_params *tzp)
+{
+ u32 efuse_calib_info, cpu_sensor;
+
+ /* Setup thermal sensor to ADC mode and setup the mux to DIODE1 */
+ airoha_init_thermal_ADC_mode(priv);
+ /* sleep 10 ms for ADC to enable */
+ usleep_range(10 * USEC_PER_MSEC, 11 * USEC_PER_MSEC);
+
+ efuse_calib_info = readl(priv->base + EN7581_EFUSE_TEMP_OFFSET_REG);
+ if (efuse_calib_info) {
+ tzp->offset = FIELD_GET(EN7581_EFUSE_TEMP_OFFSET, efuse_calib_info);
+ /* Different slope are applied if the sensor is used for CPU or for package */
+ cpu_sensor = readl(priv->base + EN7581_EFUSE_TEMP_CPU_SENSOR_REG);
+ if (cpu_sensor) {
+ tzp->slope = EN7581_SLOPE_X100_DIO_DEFAULT;
+ priv->init_temp = EN7581_INIT_TEMP_FTK_X10;
+ } else {
+ tzp->slope = EN7581_SLOPE_X100_DIO_AVS;
+ priv->init_temp = EN7581_INIT_TEMP_CPK_X10;
+ }
+ } else {
+ tzp->offset = airoha_get_thermal_ADC(priv);
+ tzp->slope = EN7581_SLOPE_X100_DIO_DEFAULT;
+ priv->init_temp = EN7581_INIT_TEMP_NONK_X10;
+ dev_info(dev, "missing thermal calibrarion EFUSE, using non calibrated value\n");
+ }
+}
+
+static void airoha_thermal_setup_monitor(struct airoha_thermal_priv *priv)
+{
+ /* Set measure mode */
+ writel(FIELD_PREP(EN7581_MSRCTL0, EN7581_MSRCTL_6SAMPLE_MAX_MIX_AVG4),
+ priv->base + EN7581_TEMPMSRCTL0);
+
+ /*
+ * Configure ADC valid reading addr
+ * The AHB temp monitor system doesn't have direct access to the
+ * thermal sensor. It does instead work by providing all kind of
+ * address to configure how to access and setup an ADC for the
+ * sensor. EN7581 supports only one sensor hence the
+ * implementation is greatly simplified but the AHB supports
+ * up to 4 different sensor from the same ADC that can be
+ * switched by tuning the ADC mux or wiriting address.
+ *
+ * We set valid instead of volt as we don't enable valid/volt
+ * split reading and AHB read valid addr in such case.
+ */
+ writel(priv->scu_adc_res.start + EN7581_DOUT_TADC,
+ priv->base + EN7581_TEMPADCVALIDADDR);
+
+ /*
+ * Configure valid bit on a fake value of bit 16. The ADC outputs
+ * max of 2 bytes for voltage.
+ */
+ writel(FIELD_PREP(EN7581_ADV_RD_VALID_POS, 16),
+ priv->base + EN7581_TEMPADCVALIDMASK);
+
+ /*
+ * AHB supports max 12 bytes for ADC voltage. Shift the read
+ * value 4 bit to the right. Precision lost by this is minimal
+ * in the order of half a °C and is acceptable in the context
+ * of triggering interrupt in critical condition.
+ */
+ writel(FIELD_PREP(EN7581_ADC_VOLTAGE_SHIFT, 4),
+ priv->base + EN7581_TEMPADCVOLTAGESHIFT);
+
+ /* BUS clock is 300MHz counting unit is 3 * 68.64 * 256 = 52.715us */
+ writel(FIELD_PREP(EN7581_PERIOD_UNIT, 3),
+ priv->base + EN7581_TEMPMONCTL1);
+
+ /*
+ * filt interval is 1 * 52.715us = 52.715us,
+ * sen interval is 379 * 52.715us = 19.97ms
+ */
+ writel(FIELD_PREP(EN7581_FILT_INTERVAL, 1) |
+ FIELD_PREP(EN7581_FILT_INTERVAL, 379),
+ priv->base + EN7581_TEMPMONCTL2);
+
+ /* AHB poll is set to 146 * 68.64 = 10.02us */
+ writel(FIELD_PREP(EN7581_ADC_POLL_INTVL, 146),
+ priv->base + EN7581_TEMPAHBPOLL);
+}
+
+static int airoha_thermal_probe(struct platform_device *pdev)
+{
+ struct thermal_zone_params tzp = { };
+ struct airoha_thermal_priv *priv;
+ struct device_node *chip_scu_np;
+ struct device *dev = &pdev->dev;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ chip_scu_np = of_parse_phandle(dev->of_node, "airoha,chip-scu", 0);
+ if (!chip_scu_np)
+ return -EINVAL;
+
+ priv->chip_scu = syscon_node_to_regmap(chip_scu_np);
+ if (IS_ERR(priv->chip_scu))
+ return PTR_ERR(priv->chip_scu);
+
+ of_address_to_resource(chip_scu_np, 0, &priv->scu_adc_res);
+ of_node_put(chip_scu_np);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ airoha_thermal_irq, IRQF_ONESHOT,
+ pdev->name, (void *)priv);
+ if (ret) {
+ dev_err(dev, "Can't get interrupt working.\n");
+ return ret;
+ }
+
+ airoha_thermal_setup_monitor(priv);
+ airoha_thermal_setup_adc_val(dev, priv, &tzp);
+
+ /* register of thermal sensor and get info from DT */
+ priv->tz = devm_thermal_of_zone_register_with_params(dev, 0, priv,
+ &thdev_ops,
+ &tzp);
+ if (IS_ERR(priv->tz)) {
+ dev_err(dev, "register thermal zone sensor failed\n");
+ return PTR_ERR(priv->tz);
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ /* Enable LOW and HIGH interrupt */
+ writel(EN7581_HOFSINTEN0 | EN7581_LOFSINTEN0,
+ priv->base + EN7581_TEMPMONINT);
+
+ return 0;
+}
+
+static const struct of_device_id airoha_thermal_match[] = {
+ { .compatible = "airoha,en7581-thermal" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, airoha_thermal_match);
+
+static struct platform_driver airoha_thermal_driver = {
+ .driver = {
+ .name = "airoha-thermal",
+ .of_match_table = airoha_thermal_match,
+ },
+ .probe = airoha_thermal_probe,
+};
+
+module_platform_driver(airoha_thermal_driver);
+
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Airoha thermal driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,304 @@
From 9dbd16ac89e00bd8640ecac3971b0943410b5cec Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Sat, 6 Jul 2024 01:15:24 +0200
Subject: [PATCH 2/2] hwrng: add support for Airoha EN7581 TRNG
Add support for Airoha TRNG. The Airoha SoC provide a True RNG module
that can output 4 bytes of raw data at times.
The module makes use of various noise source to provide True Random
Number Generation.
On probe the module is reset to operate Health Test and verify correct
execution of it.
The module can also provide DRBG function but the execution mode is
mutually exclusive, running as TRNG doesn't permit to also run it as
DRBG.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/char/hw_random/Kconfig | 13 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/airoha-trng.c | 243 +++++++++++++++++++++++++++
3 files changed, 257 insertions(+)
create mode 100644 drivers/char/hw_random/airoha-trng.c
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -62,6 +62,19 @@ config HW_RANDOM_AMD
If unsure, say Y.
+config HW_RANDOM_AIROHA
+ tristate "Airoha True HW Random Number Generator support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ default HW_RANDOM
+ help
+ This driver provides kernel-side support for the True Random Number
+ Generator hardware found on Airoha SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called airoha-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_ATMEL
tristate "Atmel Random Number Generator support"
depends on (ARCH_AT91 || COMPILE_TEST)
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -8,6 +8,7 @@ rng-core-y := core.o
obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_AIROHA) += airoha-trng.o
obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_BA431) += ba431-rng.o
obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
--- /dev/null
+++ b/drivers/char/hw_random/airoha-trng.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2024 Christian Marangi */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#define TRNG_IP_RDY 0x800
+#define CNT_TRANS GENMASK(15, 8)
+#define SAMPLE_RDY BIT(0)
+#define TRNG_NS_SEK_AND_DAT_EN 0x804
+#define RNG_EN BIT(31) /* referenced as ring_en */
+#define RAW_DATA_EN BIT(16)
+#define TRNG_HEALTH_TEST_SW_RST 0x808
+#define SW_RST BIT(0) /* Active High */
+#define TRNG_INTR_EN 0x818
+#define INTR_MASK BIT(16)
+#define CONTINUOUS_HEALTH_INITR_EN BIT(2)
+#define SW_STARTUP_INITR_EN BIT(1)
+#define RST_STARTUP_INITR_EN BIT(0)
+/* Notice that Health Test are done only out of Reset and with RNG_EN */
+#define TRNG_HEALTH_TEST_STATUS 0x824
+#define CONTINUOUS_HEALTH_AP_TEST_FAIL BIT(23)
+#define CONTINUOUS_HEALTH_RC_TEST_FAIL BIT(22)
+#define SW_STARTUP_TEST_DONE BIT(21)
+#define SW_STARTUP_AP_TEST_FAIL BIT(20)
+#define SW_STARTUP_RC_TEST_FAIL BIT(19)
+#define RST_STARTUP_TEST_DONE BIT(18)
+#define RST_STARTUP_AP_TEST_FAIL BIT(17)
+#define RST_STARTUP_RC_TEST_FAIL BIT(16)
+#define RAW_DATA_VALID BIT(7)
+
+#define TRNG_RAW_DATA_OUT 0x828
+
+#define TRNG_CNT_TRANS_VALID 0x80
+#define BUSY_LOOP_SLEEP 10
+#define BUSY_LOOP_TIMEOUT (BUSY_LOOP_SLEEP * 10000)
+
+struct airoha_trng {
+ void __iomem *base;
+ struct hwrng rng;
+ struct device *dev;
+
+ struct completion rng_op_done;
+};
+
+static int airoha_trng_irq_mask(struct airoha_trng *trng)
+{
+ u32 val;
+
+ val = readl(trng->base + TRNG_INTR_EN);
+ val |= INTR_MASK;
+ writel(val, trng->base + TRNG_INTR_EN);
+
+ return 0;
+}
+
+static int airoha_trng_irq_unmask(struct airoha_trng *trng)
+{
+ u32 val;
+
+ val = readl(trng->base + TRNG_INTR_EN);
+ val &= ~INTR_MASK;
+ writel(val, trng->base + TRNG_INTR_EN);
+
+ return 0;
+}
+
+static int airoha_trng_init(struct hwrng *rng)
+{
+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng);
+ int ret;
+ u32 val;
+
+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN);
+ val |= RNG_EN;
+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN);
+
+ /* Set out of SW Reset */
+ airoha_trng_irq_unmask(trng);
+ writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST);
+
+ ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT);
+ if (ret <= 0) {
+ dev_err(trng->dev, "Timeout waiting for Health Check\n");
+ airoha_trng_irq_mask(trng);
+ return -ENODEV;
+ }
+
+ /* Check if Health Test Failed */
+ val = readl(trng->base + TRNG_HEALTH_TEST_STATUS);
+ if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) {
+ dev_err(trng->dev, "Health Check fail: %s test fail\n",
+ val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC");
+ return -ENODEV;
+ }
+
+ /* Check if IP is ready */
+ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val,
+ val & SAMPLE_RDY, 10, 1000);
+ if (ret < 0) {
+ dev_err(trng->dev, "Timeout waiting for IP ready");
+ return -ENODEV;
+ }
+
+ /* CNT_TRANS must be 0x80 for IP to be considered ready */
+ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val,
+ FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID,
+ 10, 1000);
+ if (ret < 0) {
+ dev_err(trng->dev, "Timeout waiting for IP ready");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void airoha_trng_cleanup(struct hwrng *rng)
+{
+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng);
+ u32 val;
+
+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN);
+ val &= ~RNG_EN;
+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN);
+
+ /* Put it in SW Reset */
+ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST);
+}
+
+static int airoha_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng);
+ u32 *data = buf;
+ u32 status;
+ int ret;
+
+ ret = readl_poll_timeout(trng->base + TRNG_HEALTH_TEST_STATUS, status,
+ status & RAW_DATA_VALID, 10, 1000);
+ if (ret < 0) {
+ dev_err(trng->dev, "Timeout waiting for TRNG RAW Data valid\n");
+ return ret;
+ }
+
+ *data = readl(trng->base + TRNG_RAW_DATA_OUT);
+
+ return 4;
+}
+
+static irqreturn_t airoha_trng_irq(int irq, void *priv)
+{
+ struct airoha_trng *trng = (struct airoha_trng *)priv;
+
+ airoha_trng_irq_mask(trng);
+ /* Just complete the task, we will read the value later */
+ complete(&trng->rng_op_done);
+
+ return IRQ_HANDLED;
+}
+
+static int airoha_trng_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct airoha_trng *trng;
+ int irq, ret;
+ u32 val;
+
+ trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
+ if (!trng)
+ return -ENOMEM;
+
+ trng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ airoha_trng_irq_mask(trng);
+ ret = devm_request_irq(&pdev->dev, irq, airoha_trng_irq, 0,
+ pdev->name, (void *)trng);
+ if (ret) {
+ dev_err(dev, "Can't get interrupt working.\n");
+ return ret;
+ }
+
+ init_completion(&trng->rng_op_done);
+
+ /* Enable interrupt for SW reset Health Check */
+ val = readl(trng->base + TRNG_INTR_EN);
+ val |= RST_STARTUP_INITR_EN;
+ writel(val, trng->base + TRNG_INTR_EN);
+
+ /* Set output to raw data */
+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN);
+ val |= RAW_DATA_EN;
+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN);
+
+ /* Put it in SW Reset */
+ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST);
+
+ trng->dev = dev;
+ trng->rng.name = pdev->name;
+ trng->rng.init = airoha_trng_init;
+ trng->rng.cleanup = airoha_trng_cleanup;
+ trng->rng.read = airoha_trng_read;
+
+ ret = devm_hwrng_register(dev, &trng->rng);
+ if (ret) {
+ dev_err(dev, "failed to register rng device: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id airoha_trng_of_match[] = {
+ { .compatible = "airoha,en7581-trng", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, airoha_trng_of_match);
+
+static struct platform_driver airoha_trng_driver = {
+ .driver = {
+ .name = "airoha-trng",
+ .of_match_table = airoha_trng_of_match,
+ },
+ .probe = airoha_trng_probe,
+};
+
+module_platform_driver(airoha_trng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Airoha True Random Number Generator driver");

View File

@ -0,0 +1,268 @@
From 4019d58ca5b249e4cf79169cc0c6a4ff5275c155 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Fri, 5 Jul 2024 19:12:12 +0200
Subject: [PATCH v2 2/2] watchdog: Add support for Airoha EN7851 watchdog
Add support for Airoha EN7851 watchdog. This is a very basic watchdog
with no pretimeout support, max timeout is 28 seconds and it ticks based
on half the SoC BUS clock.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
Changes v2:
- Drop clock-frequency implementation
- Add missing bitfield.h header
- Attach BUS clock
drivers/watchdog/Kconfig | 8 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/airoha_wdt.c | 216 ++++++++++++++++++++++++++++++++++
3 files changed, 225 insertions(+)
create mode 100644 drivers/watchdog/airoha_wdt.c
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -372,6 +372,14 @@ config SL28CPLD_WATCHDOG
# ARM Architecture
+config AIROHA_WATCHDOG
+ tristate "Airoha EN7581 Watchdog"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ select WATCHDOG_CORE
+ help
+ Watchdog timer embedded into Airoha SoC. This will reboot your
+ system when the timeout is reached.
+
config ARM_SP805_WATCHDOG
tristate "ARM SP805 Watchdog"
depends on (ARM || ARM64 || COMPILE_TEST) && ARM_AMBA
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.
obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
+obj-$(CONFIG_AIROHA_WATCHDOG) += airoha_wdt.o
obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
--- /dev/null
+++ b/drivers/watchdog/airoha_wdt.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Airoha Watchdog Driver
+ *
+ * Copyright (c) 2024, AIROHA All rights reserved.
+ *
+ * Mayur Kumar <mayur.kumar@airoha.com>
+ * Christian Marangi <ansuelsmth@gmail.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/math.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+/* Base address of timer and watchdog registers */
+#define TIMER_CTRL 0x0
+#define WDT_ENABLE BIT(25)
+#define WDT_TIMER_INTERRUPT BIT(21)
+/* Timer3 is used as Watchdog Timer */
+#define WDT_TIMER_ENABLE BIT(5)
+#define WDT_TIMER_LOAD_VALUE 0x2c
+#define WDT_TIMER_CUR_VALUE 0x30
+#define WDT_TIMER_VAL GENMASK(31, 0)
+#define WDT_RELOAD 0x38
+#define WDT_RLD BIT(0)
+
+/* Airoha watchdog structure description */
+struct airoha_wdt_desc {
+ struct watchdog_device wdog_dev;
+ unsigned int wdt_freq;
+ void __iomem *base;
+};
+
+#define WDT_HEARTBEAT 24
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. (default="
+ __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int airoha_wdt_start(struct watchdog_device *wdog_dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = watchdog_get_drvdata(wdog_dev);
+ u32 val;
+
+ val = readl(airoha_wdt->base + TIMER_CTRL);
+ val |= (WDT_TIMER_ENABLE | WDT_ENABLE | WDT_TIMER_INTERRUPT);
+ writel(val, airoha_wdt->base + TIMER_CTRL);
+ val = wdog_dev->timeout * airoha_wdt->wdt_freq;
+ writel(val, airoha_wdt->base + WDT_TIMER_LOAD_VALUE);
+
+ return 0;
+}
+
+static int airoha_wdt_stop(struct watchdog_device *wdog_dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = watchdog_get_drvdata(wdog_dev);
+ u32 val;
+
+ val = readl(airoha_wdt->base + TIMER_CTRL);
+ val &= (~WDT_ENABLE & ~WDT_TIMER_ENABLE);
+ writel(val, airoha_wdt->base + TIMER_CTRL);
+
+ return 0;
+}
+
+static int airoha_wdt_ping(struct watchdog_device *wdog_dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = watchdog_get_drvdata(wdog_dev);
+ u32 val;
+
+ val = readl(airoha_wdt->base + WDT_RELOAD);
+ val |= WDT_RLD;
+ writel(val, airoha_wdt->base + WDT_RELOAD);
+
+ return 0;
+}
+
+static int airoha_wdt_set_timeout(struct watchdog_device *wdog_dev, unsigned int timeout)
+{
+ wdog_dev->timeout = timeout;
+
+ if (watchdog_active(wdog_dev)) {
+ airoha_wdt_stop(wdog_dev);
+ return airoha_wdt_start(wdog_dev);
+ }
+
+ return 0;
+}
+
+static unsigned int airoha_wdt_get_timeleft(struct watchdog_device *wdog_dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = watchdog_get_drvdata(wdog_dev);
+ u32 val;
+
+ val = readl(airoha_wdt->base + WDT_TIMER_CUR_VALUE);
+ return DIV_ROUND_UP(val, airoha_wdt->wdt_freq);
+}
+
+static const struct watchdog_info airoha_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "Airoha Watchdog",
+};
+
+static const struct watchdog_ops airoha_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = airoha_wdt_start,
+ .stop = airoha_wdt_stop,
+ .ping = airoha_wdt_ping,
+ .set_timeout = airoha_wdt_set_timeout,
+ .get_timeleft = airoha_wdt_get_timeleft,
+};
+
+static int airoha_wdt_probe(struct platform_device *pdev)
+{
+ struct airoha_wdt_desc *airoha_wdt;
+ struct watchdog_device *wdog_dev;
+ struct device *dev = &pdev->dev;
+ struct clk *bus_clk;
+ int ret;
+
+ airoha_wdt = devm_kzalloc(dev, sizeof(*airoha_wdt), GFP_KERNEL);
+ if (!airoha_wdt)
+ return -ENOMEM;
+
+ airoha_wdt->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(airoha_wdt->base))
+ return PTR_ERR(airoha_wdt->base);
+
+ bus_clk = devm_clk_get_enabled(dev, "bus");
+ if (IS_ERR(bus_clk))
+ return dev_err_probe(dev, PTR_ERR(bus_clk),
+ "failed to enable bus clock\n");
+
+ /* Watchdog ticks at half the bus rate */
+ airoha_wdt->wdt_freq = clk_get_rate(bus_clk) / 2;
+
+ /* Initialize struct watchdog device */
+ wdog_dev = &airoha_wdt->wdog_dev;
+ wdog_dev->timeout = heartbeat;
+ wdog_dev->info = &airoha_wdt_info;
+ wdog_dev->ops = &airoha_wdt_ops;
+ /* Bus 300MHz, watchdog 150MHz, 28 seconds */
+ wdog_dev->max_timeout = FIELD_MAX(WDT_TIMER_VAL) / airoha_wdt->wdt_freq;
+ wdog_dev->parent = dev;
+
+ watchdog_set_drvdata(wdog_dev, airoha_wdt);
+ watchdog_set_nowayout(wdog_dev, nowayout);
+ watchdog_stop_on_unregister(wdog_dev);
+
+ ret = devm_watchdog_register_device(dev, wdog_dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, airoha_wdt);
+ return 0;
+}
+
+static int airoha_wdt_suspend(struct device *dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(&airoha_wdt->wdog_dev))
+ airoha_wdt_stop(&airoha_wdt->wdog_dev);
+
+ return 0;
+}
+
+static int airoha_wdt_resume(struct device *dev)
+{
+ struct airoha_wdt_desc *airoha_wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(&airoha_wdt->wdog_dev)) {
+ airoha_wdt_start(&airoha_wdt->wdog_dev);
+ airoha_wdt_ping(&airoha_wdt->wdog_dev);
+ }
+ return 0;
+}
+
+static const struct of_device_id airoha_wdt_of_match[] = {
+ { .compatible = "airoha,en7581-wdt", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, airoha_wdt_of_match);
+
+static DEFINE_SIMPLE_DEV_PM_OPS(airoha_wdt_pm_ops, airoha_wdt_suspend, airoha_wdt_resume);
+
+static struct platform_driver airoha_wdt_driver = {
+ .probe = airoha_wdt_probe,
+ .driver = {
+ .name = "airoha-wdt",
+ .pm = pm_sleep_ptr(&airoha_wdt_pm_ops),
+ .of_match_table = airoha_wdt_of_match,
+ },
+};
+
+module_platform_driver(airoha_wdt_driver);
+
+MODULE_AUTHOR("Mayur Kumar <mayur.kumar@airoha.com>");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Airoha EN7581 Watchdog Driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,11 @@
--- a/drivers/i2c/busses/i2c-mt7621.c
+++ b/drivers/i2c/busses/i2c-mt7621.c
@@ -85,7 +85,7 @@ static void mtk_i2c_reset(struct mtk_i2c
{
int ret;
- ret = device_reset(i2c->adap.dev.parent);
+ ret = device_reset_optional(i2c->adap.dev.parent);
if (ret)
dev_err(i2c->dev, "I2C reset failed!\n");

View File

@ -0,0 +1,187 @@
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_en7523.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Airoha EN7523 driver.
+ *
+ * Copyright (c) 2022 Genexis Sweden AB
+ * Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include "8250.h"
+
+
+/* The Airoha UART is 16550-compatible except for the baud rate calculation.
+ *
+ * crystal_clock = 20 MHz
+ * xindiv_clock = crystal_clock / clock_div
+ * (x/y) = XYD, 32 bit register with 16 bits of x and and then 16 bits of y
+ * clock_div = XINCLK_DIVCNT (default set to 10 (0x4)),
+ * - 3 bit register [ 1, 2, 4, 8, 10, 12, 16, 20 ]
+ *
+ * baud_rate = ((xindiv_clock) * (x/y)) / ([BRDH,BRDL] * 16)
+ *
+ * XYD_y seems to need to be larger then XYD_x for things to work.
+ * Setting [BRDH,BRDL] to [0,1] and XYD_y to 65000 give even values
+ * for usual baud rates.
+ *
+ * Selecting divider needs to fulfill
+ * 1.8432 MHz <= xindiv_clk <= APB clock / 2
+ * The clocks are unknown but a divider of value 1 did not work.
+ *
+ * Optimally the XYD, BRD and XINCLK_DIVCNT registers could be searched to
+ * find values that gives the least error for every baud rate. But searching
+ * the space takes time and in practise only a few rates are of interest.
+ * With some value combinations not working a tested subset is used giving
+ * a usable range from 110 to 460800 baud.
+ */
+
+#define CLOCK_DIV_TAB_ELEMS 3
+#define XYD_Y 65000
+#define XINDIV_CLOCK 20000000
+#define UART_BRDL_20M 0x01
+#define UART_BRDH_20M 0x00
+
+static int clock_div_tab[] = { 10, 4, 2};
+static int clock_div_reg[] = { 4, 2, 1};
+
+
+int en7523_set_uart_baud_rate (struct uart_port *port, unsigned int baud)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int xyd_x, nom, denom;
+ int i;
+
+ /* set DLAB to access the baud rate divider registers (BRDH, BRDL) */
+ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+
+ /* set baud rate calculation defaults */
+
+ /* set BRDIV ([BRDH,BRDL]) to 1 */
+ serial_port_out(port, UART_BRDL, UART_BRDL_20M);
+ serial_port_out(port, UART_BRDH, UART_BRDH_20M);
+
+ /* calculate XYD_x and XINCLKDR register */
+
+ for (i = 0 ; i < CLOCK_DIV_TAB_ELEMS ; i++) {
+ denom = (XINDIV_CLOCK/40) / clock_div_tab[i];
+ nom = (baud * (XYD_Y/40));
+ xyd_x = ((nom/denom) << 4);
+ if (xyd_x < XYD_Y) break;
+ }
+
+ serial_port_out(port, UART_XINCLKDR, clock_div_reg[i]);
+ serial_port_out(port, UART_XYD, (xyd_x<<16) | XYD_Y);
+
+ /* unset DLAB */
+ serial_port_out(port, UART_LCR, up->lcr);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(en7523_set_uart_baud_rate);
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -338,6 +338,7 @@ static const struct of_device_id of_plat
{ .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
{ .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, },
{ .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, },
+ { .compatible = "airoha,en7523-uart", .data = (void *)PORT_AIROHA, },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -330,6 +330,14 @@ static const struct serial8250_config ua
.rxtrig_bytes = {1, 8, 16, 30},
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
+ [PORT_AIROHA] = {
+ .name = "Airoha 16550",
+ .fifo_size = 8,
+ .tx_loadsz = 1,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
+ .rxtrig_bytes = {1, 4},
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
@@ -2880,6 +2888,12 @@ serial8250_do_set_termios(struct uart_po
serial8250_set_divisor(port, baud, quot, frac);
+#ifdef CONFIG_SERIAL_8250_AIROHA
+ /* Airoha SoCs have custom registers for baud rate settings */
+ if (port->type == PORT_AIROHA)
+ en7523_set_uart_baud_rate(port, baud);
+#endif
+
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
* is written without DLAB set, this mode will be disabled.
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SERIAL_8250_PERICOM) += 825
obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o
obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o
obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o
+obj-$(CONFIG_SERIAL_8250_AIROHA) += 8250_en7523.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
--- a/include/uapi/linux/serial_reg.h
+++ b/include/uapi/linux/serial_reg.h
@@ -382,5 +382,17 @@
#define UART_ALTR_EN_TXFIFO_LW 0x01 /* Enable the TX FIFO Low Watermark */
#define UART_ALTR_TX_LOW 0x41 /* Tx FIFO Low Watermark */
+/*
+ * These are definitions for the Airoha EN75XX uart registers
+ * Normalized because of 32 bits registers.
+ */
+#define UART_BRDL 0
+#define UART_BRDH 1
+#define UART_XINCLKDR 10
+#define UART_XYD 11
+#define UART_TXLVLCNT 12
+#define UART_RXLVLCNT 13
+#define UART_FINTLVL 14
+
#endif /* _LINUX_SERIAL_REG_H */
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -45,6 +45,7 @@
#define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
#define PORT_RT2880 29 /* Ralink RT2880 internal UART */
#define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
+#define PORT_AIROHA 31 /* Airoha 16550 UART */
/*
* ARM specific type numbers. These are not currently guaranteed
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -195,6 +195,7 @@ void serial8250_do_set_mctrl(struct uart
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac);
int fsl8250_handle_irq(struct uart_port *port);
+int en7523_set_uart_baud_rate(struct uart_port *port, unsigned int baud);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr);
void serial8250_read_char(struct uart_8250_port *up, u16 lsr);

View File

@ -0,0 +1,60 @@
From 64e497f372dfca3e6be9fe05a0f9b874ea8604d2 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:46 +0200
Subject: [PATCH 1/6] clk: en7523: remove REG_PCIE*_{MEM,MEM_MASK}
configuration
REG_PCIE*_MEM and REG_PCIE*_MEM_MASK regs (PBUS_CSR memory region) are not
part of the scu block on the EN7581 SoC and they are used to select the
PCIE ports on the PBUS, so remove this configuration from the clock driver
and set these registers in the PCIE host driver instead.
This patch does not introduce any backward incompatibility since the dts
for EN7581 SoC is not upstream yet.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 18 ------------------
1 file changed, 18 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -31,12 +31,6 @@
#define REG_RESET_CONTROL_PCIE1 BIT(27)
#define REG_RESET_CONTROL_PCIE2 BIT(26)
/* EN7581 */
-#define REG_PCIE0_MEM 0x00
-#define REG_PCIE0_MEM_MASK 0x04
-#define REG_PCIE1_MEM 0x08
-#define REG_PCIE1_MEM_MASK 0x0c
-#define REG_PCIE2_MEM 0x10
-#define REG_PCIE2_MEM_MASK 0x14
#define REG_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
@@ -415,26 +409,14 @@ static void en7581_pci_disable(struct cl
static int en7581_clk_hw_init(struct platform_device *pdev,
void __iomem *np_base)
{
- void __iomem *pb_base;
u32 val;
- pb_base = devm_platform_ioremap_resource(pdev, 3);
- if (IS_ERR(pb_base))
- return PTR_ERR(pb_base);
-
val = readl(np_base + REG_NP_SCU_SSTR);
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
writel(val, np_base + REG_NP_SCU_SSTR);
val = readl(np_base + REG_NP_SCU_PCIC);
writel(val | 3, np_base + REG_NP_SCU_PCIC);
- writel(0x20000000, pb_base + REG_PCIE0_MEM);
- writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK);
- writel(0x24000000, pb_base + REG_PCIE1_MEM);
- writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK);
- writel(0x28000000, pb_base + REG_PCIE2_MEM);
- writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
-
return 0;
}

View File

@ -0,0 +1,144 @@
From 0dd8a6df58a4a8cf1f341249e7358b3bb51f52ad Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:47 +0200
Subject: [PATCH 2/6] clk: en7523: move clock_register in hw_init callback
Move en7523_register_clocks routine in hw_init callback.
Introduce en7523_clk_hw_init callback for EN7523 SoC.
This is a preliminary patch to differentiate IO mapped region between
EN7523 and EN7581 SoCs in order to access chip-scu IO region
<0x1fa20000 0x384> on EN7581 SoC as syscon device since it contains
miscellaneous registers needed by multiple devices (clock, pinctrl ..).
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 82 ++++++++++++++++++++++++----------------
1 file changed, 50 insertions(+), 32 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -78,7 +78,8 @@ struct en_clk_soc_data {
const u16 *idx_map;
u16 idx_map_nr;
} reset;
- int (*hw_init)(struct platform_device *pdev, void __iomem *np_base);
+ int (*hw_init)(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data);
};
static const u32 gsw_base[] = { 400000000, 500000000 };
@@ -406,20 +407,6 @@ static void en7581_pci_disable(struct cl
usleep_range(1000, 2000);
}
-static int en7581_clk_hw_init(struct platform_device *pdev,
- void __iomem *np_base)
-{
- u32 val;
-
- val = readl(np_base + REG_NP_SCU_SSTR);
- val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
- writel(val, np_base + REG_NP_SCU_SSTR);
- val = readl(np_base + REG_NP_SCU_PCIC);
- writel(val | 3, np_base + REG_NP_SCU_PCIC);
-
- return 0;
-}
-
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
void __iomem *base, void __iomem *np_base)
{
@@ -449,6 +436,49 @@ static void en7523_register_clocks(struc
clk_data->num = EN7523_NUM_CLOCKS;
}
+static int en7523_clk_hw_init(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data)
+{
+ void __iomem *base, *np_base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ np_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(np_base))
+ return PTR_ERR(np_base);
+
+ en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
+
+ return 0;
+}
+
+static int en7581_clk_hw_init(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data)
+{
+ void __iomem *base, *np_base;
+ u32 val;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ np_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(np_base))
+ return PTR_ERR(np_base);
+
+ en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
+
+ val = readl(np_base + REG_NP_SCU_SSTR);
+ val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
+ writel(val, np_base + REG_NP_SCU_SSTR);
+ val = readl(np_base + REG_NP_SCU_PCIC);
+ writel(val | 3, np_base + REG_NP_SCU_PCIC);
+
+ return 0;
+}
+
static int en7523_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@@ -543,31 +573,18 @@ static int en7523_clk_probe(struct platf
struct device_node *node = pdev->dev.of_node;
const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
- void __iomem *base, *np_base;
int r;
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- np_base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(np_base))
- return PTR_ERR(np_base);
-
- soc_data = device_get_match_data(&pdev->dev);
- if (soc_data->hw_init) {
- r = soc_data->hw_init(pdev, np_base);
- if (r)
- return r;
- }
-
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
- en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
+ soc_data = device_get_match_data(&pdev->dev);
+ r = soc_data->hw_init(pdev, clk_data);
+ if (r)
+ return r;
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
@@ -590,6 +607,7 @@ static const struct en_clk_soc_data en75
.prepare = en7523_pci_prepare,
.unprepare = en7523_pci_unprepare,
},
+ .hw_init = en7523_clk_hw_init,
};
static const struct en_clk_soc_data en7581_data = {

View File

@ -0,0 +1,160 @@
From f849bcb746abeaafa63b4f02f1d8bb22703fc645 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:48 +0200
Subject: [PATCH 3/6] clk: en7523: introduce chip_scu regmap
Introduce chip_scu regmap pointer since EN7581 SoC will access chip-scu
memory area via a syscon node. Remove first memory region mapping
for EN7581 SoC. This patch does not introduce any backward incompatibility
since the dts for EN7581 SoC is not upstream yet.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 81 ++++++++++++++++++++++++++++++----------
1 file changed, 61 insertions(+), 20 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -3,8 +3,10 @@
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/clock/en7523-clk.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
@@ -247,15 +249,11 @@ static const u16 en7581_rst_map[] = {
[EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
};
-static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
+static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val)
{
- const struct en_clk_desc *desc = &en7523_base_clks[i];
- u32 val;
-
if (!desc->base_bits)
return desc->base_value;
- val = readl(base + desc->base_reg);
val >>= desc->base_shift;
val &= (1 << desc->base_bits) - 1;
@@ -265,16 +263,11 @@ static unsigned int en7523_get_base_rate
return desc->base_values[val];
}
-static u32 en7523_get_div(void __iomem *base, int i)
+static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val)
{
- const struct en_clk_desc *desc = &en7523_base_clks[i];
- u32 reg, val;
-
if (!desc->div_bits)
return 1;
- reg = desc->div_reg ? desc->div_reg : desc->base_reg;
- val = readl(base + reg);
val >>= desc->div_shift;
val &= (1 << desc->div_bits) - 1;
@@ -416,9 +409,12 @@ static void en7523_register_clocks(struc
for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
const struct en_clk_desc *desc = &en7523_base_clks[i];
+ u32 reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+ u32 val = readl(base + desc->base_reg);
- rate = en7523_get_base_rate(base, i);
- rate /= en7523_get_div(base, i);
+ rate = en7523_get_base_rate(desc, val);
+ val = readl(base + reg);
+ rate /= en7523_get_div(desc, val);
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
@@ -454,21 +450,66 @@ static int en7523_clk_hw_init(struct pla
return 0;
}
+static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
+ struct regmap *map, void __iomem *base)
+{
+ struct clk_hw *hw;
+ u32 rate;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
+ const struct en_clk_desc *desc = &en7523_base_clks[i];
+ u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+ int err;
+
+ err = regmap_read(map, desc->base_reg, &val);
+ if (err) {
+ pr_err("Failed reading fixed clk rate %s: %d\n",
+ desc->name, err);
+ continue;
+ }
+ rate = en7523_get_base_rate(desc, val);
+
+ err = regmap_read(map, reg, &val);
+ if (err) {
+ pr_err("Failed reading fixed clk div %s: %d\n",
+ desc->name, err);
+ continue;
+ }
+ rate /= en7523_get_div(desc, val);
+
+ hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
+ if (IS_ERR(hw)) {
+ pr_err("Failed to register clk %s: %ld\n",
+ desc->name, PTR_ERR(hw));
+ continue;
+ }
+
+ clk_data->hws[desc->id] = hw;
+ }
+
+ hw = en7523_register_pcie_clk(dev, base);
+ clk_data->hws[EN7523_CLK_PCIE] = hw;
+
+ clk_data->num = EN7523_NUM_CLOCKS;
+}
+
static int en7581_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *base, *np_base;
+ void __iomem *np_base;
+ struct regmap *map;
u32 val;
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
+ if (IS_ERR(map))
+ return PTR_ERR(map);
- np_base = devm_platform_ioremap_resource(pdev, 1);
+ np_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(np_base))
return PTR_ERR(np_base);
- en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
+ en7581_register_clocks(&pdev->dev, clk_data, map, np_base);
val = readl(np_base + REG_NP_SCU_SSTR);
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
@@ -545,7 +586,7 @@ static int en7523_reset_register(struct
if (!soc_data->reset.idx_map_nr)
return 0;
- base = devm_platform_ioremap_resource(pdev, 2);
+ base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(base))
return PTR_ERR(base);

View File

@ -0,0 +1,150 @@
From b9ea4918216ca0c2511446c531d3f8163ac1466d Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:49 +0200
Subject: [PATCH 4/6] clk: en7523: fix estimation of fixed rate for EN7581
Introduce en7581_base_clks array in order to define per-SoC fixed-rate
clock parameters and fix wrong parameters for emi, npu and crypto EN7581
clocks
Fixes: 66bc47326ce2 ("clk: en7523: Add EN7581 support")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 105 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 103 insertions(+), 2 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -37,6 +37,7 @@
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_CRYPTO_CLKSRC2 0x20c
#define REG_RST_CTRL2 0x00
#define REG_RST_CTRL1 0x04
@@ -89,6 +90,10 @@ static const u32 emi_base[] = { 33300000
static const u32 bus_base[] = { 500000000, 540000000 };
static const u32 slic_base[] = { 100000000, 3125000 };
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
+/* EN7581 */
+static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
+static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
+static const u32 crypto_base[] = { 540000000, 480000000 };
static const struct en_clk_desc en7523_base_clks[] = {
{
@@ -186,6 +191,102 @@ static const struct en_clk_desc en7523_b
}
};
+static const struct en_clk_desc en7581_base_clks[] = {
+ {
+ .id = EN7523_CLK_GSW,
+ .name = "gsw",
+
+ .base_reg = REG_GSW_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = gsw_base,
+ .n_base_values = ARRAY_SIZE(gsw_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_EMI,
+ .name = "emi",
+
+ .base_reg = REG_EMI_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = emi7581_base,
+ .n_base_values = ARRAY_SIZE(emi7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_BUS,
+ .name = "bus",
+
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = bus_base,
+ .n_base_values = ARRAY_SIZE(bus_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_SLIC,
+ .name = "slic",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = slic_base,
+ .n_base_values = ARRAY_SIZE(slic_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 24,
+ .div_val0 = 20,
+ .div_step = 2,
+ }, {
+ .id = EN7523_CLK_SPI,
+ .name = "spi",
+
+ .base_reg = REG_SPI_CLK_DIV_SEL,
+
+ .base_value = 400000000,
+
+ .div_bits = 5,
+ .div_shift = 8,
+ .div_val0 = 40,
+ .div_step = 2,
+ }, {
+ .id = EN7523_CLK_NPU,
+ .name = "npu",
+
+ .base_reg = REG_NPU_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = npu7581_base,
+ .n_base_values = ARRAY_SIZE(npu7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_CRYPTO,
+ .name = "crypto",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = crypto_base,
+ .n_base_values = ARRAY_SIZE(crypto_base),
+ }
+};
+
static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL2,
REG_RST_CTRL1,
@@ -457,8 +558,8 @@ static void en7581_register_clocks(struc
u32 rate;
int i;
- for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
- const struct en_clk_desc *desc = &en7523_base_clks[i];
+ for (i = 0; i < ARRAY_SIZE(en7581_base_clks); i++) {
+ const struct en_clk_desc *desc = &en7581_base_clks[i];
u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg;
int err;

View File

@ -0,0 +1,172 @@
From 2c5b1a5b68973947a6919d9c951f9b3e0d84f347 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:50 +0200
Subject: [PATCH 5/6] clk: en7523: move en7581_reset_register() in
en7581_clk_hw_init()
Move en7581_reset_register routine in en7581_clk_hw_init() since reset
feature is supported just by EN7581 SoC.
Get rid of reset struct in en_clk_soc_data data struct.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 93 ++++++++++++++--------------------------
1 file changed, 33 insertions(+), 60 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -76,11 +76,6 @@ struct en_rst_data {
struct en_clk_soc_data {
const struct clk_ops pcie_ops;
- struct {
- const u16 *bank_ofs;
- const u16 *idx_map;
- u16 idx_map_nr;
- } reset;
int (*hw_init)(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data);
};
@@ -595,32 +590,6 @@ static void en7581_register_clocks(struc
clk_data->num = EN7523_NUM_CLOCKS;
}
-static int en7581_clk_hw_init(struct platform_device *pdev,
- struct clk_hw_onecell_data *clk_data)
-{
- void __iomem *np_base;
- struct regmap *map;
- u32 val;
-
- map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
- if (IS_ERR(map))
- return PTR_ERR(map);
-
- np_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(np_base))
- return PTR_ERR(np_base);
-
- en7581_register_clocks(&pdev->dev, clk_data, map, np_base);
-
- val = readl(np_base + REG_NP_SCU_SSTR);
- val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
- writel(val, np_base + REG_NP_SCU_SSTR);
- val = readl(np_base + REG_NP_SCU_PCIC);
- writel(val | 3, np_base + REG_NP_SCU_PCIC);
-
- return 0;
-}
-
static int en7523_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@@ -670,23 +639,18 @@ static int en7523_reset_xlate(struct res
return rst_data->idx_map[reset_spec->args[0]];
}
-static const struct reset_control_ops en7523_reset_ops = {
+static const struct reset_control_ops en7581_reset_ops = {
.assert = en7523_reset_assert,
.deassert = en7523_reset_deassert,
.status = en7523_reset_status,
};
-static int en7523_reset_register(struct platform_device *pdev,
- const struct en_clk_soc_data *soc_data)
+static int en7581_reset_register(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct en_rst_data *rst_data;
void __iomem *base;
- /* no reset lines available */
- if (!soc_data->reset.idx_map_nr)
- return 0;
-
base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -695,13 +659,13 @@ static int en7523_reset_register(struct
if (!rst_data)
return -ENOMEM;
- rst_data->bank_ofs = soc_data->reset.bank_ofs;
- rst_data->idx_map = soc_data->reset.idx_map;
+ rst_data->bank_ofs = en7581_rst_ofs;
+ rst_data->idx_map = en7581_rst_map;
rst_data->base = base;
- rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr;
+ rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map);
rst_data->rcdev.of_xlate = en7523_reset_xlate;
- rst_data->rcdev.ops = &en7523_reset_ops;
+ rst_data->rcdev.ops = &en7581_reset_ops;
rst_data->rcdev.of_node = dev->of_node;
rst_data->rcdev.of_reset_n_cells = 1;
rst_data->rcdev.owner = THIS_MODULE;
@@ -710,6 +674,32 @@ static int en7523_reset_register(struct
return devm_reset_controller_register(dev, &rst_data->rcdev);
}
+static int en7581_clk_hw_init(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data)
+{
+ void __iomem *np_base;
+ struct regmap *map;
+ u32 val;
+
+ map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ np_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(np_base))
+ return PTR_ERR(np_base);
+
+ en7581_register_clocks(&pdev->dev, clk_data, map, np_base);
+
+ val = readl(np_base + REG_NP_SCU_SSTR);
+ val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
+ writel(val, np_base + REG_NP_SCU_SSTR);
+ val = readl(np_base + REG_NP_SCU_PCIC);
+ writel(val | 3, np_base + REG_NP_SCU_PCIC);
+
+ return en7581_reset_register(pdev);
+}
+
static int en7523_clk_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -728,19 +718,7 @@ static int en7523_clk_probe(struct platf
if (r)
return r;
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n",
- pdev->name);
-
- r = en7523_reset_register(pdev, soc_data);
- if (r) {
- of_clk_del_provider(node);
- return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n",
- pdev->name);
- }
-
- return 0;
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
static const struct en_clk_soc_data en7523_data = {
@@ -758,11 +736,6 @@ static const struct en_clk_soc_data en75
.enable = en7581_pci_enable,
.disable = en7581_pci_disable,
},
- .reset = {
- .bank_ofs = en7581_rst_ofs,
- .idx_map = en7581_rst_map,
- .idx_map_nr = ARRAY_SIZE(en7581_rst_map),
- },
.hw_init = en7581_clk_hw_init,
};

View File

@ -0,0 +1,82 @@
From 665a59f4836c3d7813a9d8bfb9680d93adb4626e Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 3 Sep 2024 23:39:51 +0200
Subject: [PATCH 6/6] clk: en7523: map io region in a single block
Map all clock-controller memory region in a single block.
This patch does not introduce any backward incompatibility since the dts
for EN7581 SoC is not upstream yet.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/clk/clk-en7523.c | 32 +++++++++++++-------------------
1 file changed, 13 insertions(+), 19 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -39,8 +39,8 @@
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
#define REG_CRYPTO_CLKSRC2 0x20c
-#define REG_RST_CTRL2 0x00
-#define REG_RST_CTRL1 0x04
+#define REG_RST_CTRL2 0x830
+#define REG_RST_CTRL1 0x834
struct en_clk_desc {
int id;
@@ -645,15 +645,9 @@ static const struct reset_control_ops en
.status = en7523_reset_status,
};
-static int en7581_reset_register(struct platform_device *pdev)
+static int en7581_reset_register(struct device *dev, void __iomem *base)
{
- struct device *dev = &pdev->dev;
struct en_rst_data *rst_data;
- void __iomem *base;
-
- base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(base))
- return PTR_ERR(base);
rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
if (!rst_data)
@@ -677,27 +671,27 @@ static int en7581_reset_register(struct
static int en7581_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *np_base;
struct regmap *map;
+ void __iomem *base;
u32 val;
map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
if (IS_ERR(map))
return PTR_ERR(map);
- np_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(np_base))
- return PTR_ERR(np_base);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- en7581_register_clocks(&pdev->dev, clk_data, map, np_base);
+ en7581_register_clocks(&pdev->dev, clk_data, map, base);
- val = readl(np_base + REG_NP_SCU_SSTR);
+ val = readl(base + REG_NP_SCU_SSTR);
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
- writel(val, np_base + REG_NP_SCU_SSTR);
- val = readl(np_base + REG_NP_SCU_PCIC);
- writel(val | 3, np_base + REG_NP_SCU_PCIC);
+ writel(val, base + REG_NP_SCU_SSTR);
+ val = readl(base + REG_NP_SCU_PCIC);
+ writel(val | 3, base + REG_NP_SCU_PCIC);
- return en7581_reset_register(pdev);
+ return en7581_reset_register(&pdev->dev, base);
}
static int en7523_clk_probe(struct platform_device *pdev)

View File

@ -0,0 +1,474 @@
From b235c45e83c8c2a24746652982d569896b142de9 Mon Sep 17 00:00:00 2001
From: Benjamin Larsson <benjamin.larsson@genexis.eu>
Date: Wed, 16 Oct 2024 12:07:34 +0200
Subject: [PATCH 2/2] pwm: airoha: Add support for EN7581 SoC
Introduce driver for PWM module available on EN7581 SoC.
Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/pwm/Kconfig | 11 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-airoha.c | 424 +++++++++++++++++++++++++++++++++++++++
3 files changed, 436 insertions(+)
create mode 100644 drivers/pwm/pwm-airoha.c
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -51,6 +51,17 @@ config PWM_AB8500
To compile this driver as a module, choose M here: the module
will be called pwm-ab8500.
+config PWM_AIROHA
+ tristate "Airoha PWM support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ select REGMAP_MMIO
+ help
+ Generic PWM framework driver for Airoha SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-airoha.
+
config PWM_APPLE
tristate "Apple SoC PWM support"
depends on ARCH_APPLE || COMPILE_TEST
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_SYSFS) += sysfs.o
obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
+obj-$(CONFIG_PWM_AIROHA) += pwm-airoha.o
obj-$(CONFIG_PWM_APPLE) += pwm-apple.o
obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
--- /dev/null
+++ b/drivers/pwm/pwm-airoha.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 Markus Gothe <markus.gothe@genexis.eu>
+ *
+ * Limitations:
+ * - No disable bit, so a disabled PWM is simulated by setting duty_cycle to 0
+ * - Only 8 concurrent waveform generators are available for 8 combinations of
+ * duty_cycle and period. Waveform generators are shared between 16 GPIO
+ * pins and 17 SIPO GPIO pins.
+ * - Supports only normal polarity.
+ * - On configuration the currently running period is completed.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <asm/div64.h>
+
+#define REG_SGPIO_LED_DATA 0x0024
+#define SGPIO_LED_DATA_SHIFT_FLAG BIT(31)
+#define SGPIO_LED_DATA_DATA GENMASK(16, 0)
+
+#define REG_SGPIO_CLK_DIVR 0x0028
+#define REG_SGPIO_CLK_DLY 0x002c
+
+#define REG_SIPO_FLASH_MODE_CFG 0x0030
+#define SERIAL_GPIO_FLASH_MODE BIT(1)
+#define SERIAL_GPIO_MODE BIT(0)
+
+#define REG_GPIO_FLASH_PRD_SET(_n) (0x003c + ((_n) << 2))
+#define GPIO_FLASH_PRD_MASK(_n) GENMASK(15 + ((_n) << 4), ((_n) << 4))
+
+#define REG_GPIO_FLASH_MAP(_n) (0x004c + ((_n) << 2))
+#define GPIO_FLASH_SETID_MASK(_n) GENMASK(2 + ((_n) << 2), ((_n) << 2))
+#define GPIO_FLASH_EN(_n) BIT(3 + ((_n) << 2))
+
+#define REG_SIPO_FLASH_MAP(_n) (0x0054 + ((_n) << 2))
+
+#define REG_CYCLE_CFG_VALUE(_n) (0x0098 + ((_n) << 2))
+#define WAVE_GEN_CYCLE_MASK(_n) GENMASK(7 + ((_n) << 3), ((_n) << 3))
+
+#define EN7581_NUM_BUCKETS 8
+
+struct airoha_pwm_bucket {
+ /* Bitmask of PWM channels using this bucket */
+ u64 used;
+ u64 period_ns;
+ u64 duty_ns;
+};
+
+struct airoha_pwm {
+ struct pwm_chip chip;
+
+ struct regmap *regmap;
+
+ struct device_node *np;
+ u64 initialized;
+
+ struct airoha_pwm_bucket bucket[EN7581_NUM_BUCKETS];
+};
+
+/*
+ * The first 16 GPIO pins, GPIO0-GPIO15, are mapped into 16 PWM channels, 0-15.
+ * The SIPO GPIO pins are 17 pins which are mapped into 17 PWM channels, 16-32.
+ * However, we've only got 8 concurrent waveform generators and can therefore
+ * only use up to 8 different combinations of duty cycle and period at a time.
+ */
+#define PWM_NUM_GPIO 16
+#define PWM_NUM_SIPO 17
+
+/* The PWM hardware supports periods between 4 ms and 1 s */
+#define PERIOD_MIN_NS (4 * NSEC_PER_MSEC)
+#define PERIOD_MAX_NS (1 * NSEC_PER_SEC)
+/* It is represented internally as 1/250 s between 1 and 250 */
+#define PERIOD_MIN 1
+#define PERIOD_MAX 250
+/* Duty cycle is relative with 255 corresponding to 100% */
+#define DUTY_FULL 255
+
+static int airoha_pwm_get_generator(struct airoha_pwm *pc, u64 duty_ns,
+ u64 period_ns)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (!pc->bucket[i].used)
+ continue;
+
+ if (duty_ns == pc->bucket[i].duty_ns &&
+ period_ns == pc->bucket[i].period_ns)
+ return i;
+
+ /*
+ * Unlike duty cycle zero, which can be handled by
+ * disabling PWM, a generator is needed for full duty
+ * cycle but it can be reused regardless of period
+ */
+ if (duty_ns == DUTY_FULL && pc->bucket[i].duty_ns == DUTY_FULL)
+ return i;
+ }
+
+ return -1;
+}
+
+static void airoha_pwm_release_bucket_config(struct airoha_pwm *pc,
+ unsigned int hwpwm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++)
+ pc->bucket[i].used &= ~BIT_ULL(hwpwm);
+}
+
+static int airoha_pwm_consume_generator(struct airoha_pwm *pc,
+ u64 duty_ns, u64 period_ns,
+ unsigned int hwpwm)
+{
+ int id = airoha_pwm_get_generator(pc, duty_ns, period_ns);
+
+ if (id < 0) {
+ int i;
+
+ /* find an unused waveform generator */
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (!(pc->bucket[i].used & ~BIT_ULL(hwpwm))) {
+ id = i;
+ break;
+ }
+ }
+ }
+
+ if (id >= 0) {
+ airoha_pwm_release_bucket_config(pc, hwpwm);
+ pc->bucket[id].used |= BIT_ULL(hwpwm);
+ pc->bucket[id].period_ns = period_ns;
+ pc->bucket[id].duty_ns = duty_ns;
+ }
+
+ return id;
+}
+
+static int airoha_pwm_sipo_init(struct airoha_pwm *pc)
+{
+ u32 clk_divr_val, sipo_clock_delay, sipo_clock_divisor;
+ u32 val;
+
+ if (!(pc->initialized >> PWM_NUM_GPIO))
+ return 0;
+
+ /*
+ * Select the right shift register chip.
+ * By default 74HC164 is assumed. With this enabled
+ * 74HC595 chip is used that requires the latch pin
+ * to be triggered to apply the configuration.
+ */
+ if (of_property_read_bool(pc->np, "airoha,74hc595-mode"))
+ regmap_set_bits(pc->regmap, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_MODE);
+ else
+ regmap_clear_bits(pc->regmap, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_MODE);
+
+ if (of_property_read_u32(pc->np, "airoha,sipo-clock-divisor",
+ &sipo_clock_divisor))
+ sipo_clock_divisor = 32;
+
+ switch (sipo_clock_divisor) {
+ case 4:
+ clk_divr_val = 0;
+ break;
+ case 8:
+ clk_divr_val = 1;
+ break;
+ case 16:
+ clk_divr_val = 2;
+ break;
+ case 32:
+ clk_divr_val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Configure shift register timings */
+ regmap_write(pc->regmap, REG_SGPIO_CLK_DIVR, clk_divr_val);
+
+ if (of_property_read_u32(pc->np, "airoha,sipo-clock-delay",
+ &sipo_clock_delay))
+ sipo_clock_delay = 1;
+
+ if (sipo_clock_delay < 1 || sipo_clock_delay > sipo_clock_divisor / 2)
+ return -EINVAL;
+
+ /*
+ * The actual delay is sclkdly + 1 so subtract 1 from
+ * sipo-clock-delay to calculate the register value
+ */
+ sipo_clock_delay--;
+ regmap_write(pc->regmap, REG_SGPIO_CLK_DLY, sipo_clock_delay);
+
+ /*
+ * It it necessary to after muxing explicitly shift out all
+ * zeroes to initialize the shift register before enabling PWM
+ * mode because in PWM mode SIPO will not start shifting until
+ * it needs to output a non-zero value (bit 31 of led_data
+ * indicates shifting in progress and it must return to zero
+ * before led_data can be written or PWM mode can be set)
+ */
+ if (regmap_read_poll_timeout(pc->regmap, REG_SGPIO_LED_DATA, val,
+ !(val & SGPIO_LED_DATA_SHIFT_FLAG), 10,
+ 200 * USEC_PER_MSEC))
+ return -ETIMEDOUT;
+
+ regmap_clear_bits(pc->regmap, REG_SGPIO_LED_DATA, SGPIO_LED_DATA_DATA);
+ if (regmap_read_poll_timeout(pc->regmap, REG_SGPIO_LED_DATA, val,
+ !(val & SGPIO_LED_DATA_SHIFT_FLAG), 10,
+ 200 * USEC_PER_MSEC))
+ return -ETIMEDOUT;
+
+ /* Set SIPO in PWM mode */
+ regmap_set_bits(pc->regmap, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_FLASH_MODE);
+
+ return 0;
+}
+
+static void airoha_pwm_calc_bucket_config(struct airoha_pwm *pc, int index,
+ u64 duty_ns, u64 period_ns)
+{
+ u32 period, duty, mask, val;
+ u64 tmp;
+
+ tmp = duty_ns * DUTY_FULL;
+ duty = clamp_val(div64_u64(tmp, period_ns), 0, DUTY_FULL);
+ tmp = period_ns * 25;
+ period = clamp_val(div64_u64(tmp, 100000000), PERIOD_MIN, PERIOD_MAX);
+
+ /* Configure frequency divisor */
+ mask = WAVE_GEN_CYCLE_MASK(index % 4);
+ val = (period << __ffs(mask)) & mask;
+ regmap_update_bits(pc->regmap, REG_CYCLE_CFG_VALUE(index / 4),
+ mask, val);
+
+ /* Configure duty cycle */
+ duty = ((DUTY_FULL - duty) << 8) | duty;
+ mask = GPIO_FLASH_PRD_MASK(index % 2);
+ val = (duty << __ffs(mask)) & mask;
+ regmap_update_bits(pc->regmap, REG_GPIO_FLASH_PRD_SET(index / 2),
+ mask, val);
+}
+
+static void airoha_pwm_config_flash_map(struct airoha_pwm *pc,
+ unsigned int hwpwm, int index)
+{
+ u32 addr, mask, val;
+
+ if (hwpwm < PWM_NUM_GPIO) {
+ addr = REG_GPIO_FLASH_MAP(hwpwm / 8);
+ } else {
+ addr = REG_SIPO_FLASH_MAP(hwpwm / 8);
+ hwpwm -= PWM_NUM_GPIO;
+ }
+
+ if (index < 0) {
+ /*
+ * Change of waveform takes effect immediately but
+ * disabling has some delay so to prevent glitching
+ * only the enable bit is touched when disabling
+ */
+ regmap_clear_bits(pc->regmap, addr, GPIO_FLASH_EN(hwpwm % 8));
+ return;
+ }
+
+ mask = GPIO_FLASH_SETID_MASK(hwpwm % 8);
+ val = ((index & 7) << __ffs(mask)) & mask;
+ regmap_update_bits(pc->regmap, addr, mask, val);
+ regmap_set_bits(pc->regmap, addr, GPIO_FLASH_EN(hwpwm % 8));
+}
+
+static int airoha_pwm_config(struct airoha_pwm *pc, struct pwm_device *pwm,
+ u64 duty_ns, u64 period_ns)
+{
+ int index = -1;
+
+ index = airoha_pwm_consume_generator(pc, duty_ns, period_ns,
+ pwm->hwpwm);
+ if (index < 0)
+ return -EBUSY;
+
+ if (!(pc->initialized & BIT_ULL(pwm->hwpwm)) &&
+ pwm->hwpwm >= PWM_NUM_GPIO)
+ airoha_pwm_sipo_init(pc);
+
+ if (index >= 0) {
+ airoha_pwm_calc_bucket_config(pc, index, duty_ns, period_ns);
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, index);
+ } else {
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, index);
+ airoha_pwm_release_bucket_config(pc, pwm->hwpwm);
+ }
+
+ pc->initialized |= BIT_ULL(pwm->hwpwm);
+
+ return 0;
+}
+
+static void airoha_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+
+ /* Disable PWM and release the waveform */
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, -1);
+ airoha_pwm_release_bucket_config(pc, pwm->hwpwm);
+
+ pc->initialized &= ~BIT_ULL(pwm->hwpwm);
+ if (!(pc->initialized >> PWM_NUM_GPIO))
+ regmap_clear_bits(pc->regmap, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_FLASH_MODE);
+}
+
+static int airoha_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+ u64 duty = state->enabled ? state->duty_cycle : 0;
+ u64 period = state->period;
+
+ /* Only normal polarity is supported */
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ return -EINVAL;
+
+ if (!state->enabled) {
+ airoha_pwm_disable(chip, pwm);
+ return 0;
+ }
+
+ if (period < PERIOD_MIN_NS)
+ return -EINVAL;
+
+ if (period > PERIOD_MAX_NS)
+ period = PERIOD_MAX_NS;
+
+ return airoha_pwm_config(pc, pwm, duty, period);
+}
+
+static int airoha_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+ int i;
+
+ /* find hwpwm in waveform generator bucket */
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (pc->bucket[i].used & BIT_ULL(pwm->hwpwm)) {
+ state->enabled = pc->initialized & BIT_ULL(pwm->hwpwm);
+ state->polarity = PWM_POLARITY_NORMAL;
+ state->period = pc->bucket[i].period_ns;
+ state->duty_cycle = pc->bucket[i].duty_ns;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(pc->bucket))
+ state->enabled = false;
+
+ return 0;
+}
+
+static const struct pwm_ops airoha_pwm_ops = {
+ .get_state = airoha_pwm_get_state,
+ .apply = airoha_pwm_apply,
+};
+
+static int airoha_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct airoha_pwm *pc;
+ struct pwm_chip *chip;
+
+ chip = devm_pwmchip_alloc(dev, PWM_NUM_GPIO + PWM_NUM_SIPO,
+ sizeof(*pc));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ chip->ops = &airoha_pwm_ops;
+ pc = pwmchip_get_drvdata(chip);
+ pc->np = dev->of_node;
+
+ pc->regmap = device_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(pc->regmap))
+ return PTR_ERR(pc->regmap);
+
+ return devm_pwmchip_add(&pdev->dev, chip);
+}
+
+static const struct of_device_id airoha_pwm_of_match[] = {
+ { .compatible = "airoha,en7581-pwm" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, airoha_pwm_of_match);
+
+static struct platform_driver airoha_pwm_driver = {
+ .driver = {
+ .name = "pwm-airoha",
+ .of_match_table = airoha_pwm_of_match,
+ },
+ .probe = airoha_pwm_probe,
+};
+module_platform_driver(airoha_pwm_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_AUTHOR("Markus Gothe <markus.gothe@genexis.eu>");
+MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
+MODULE_DESCRIPTION("Airoha EN7581 PWM driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,45 @@
From 6d74b9e6d3bb07f50b22b9ea047b84a83aba185c Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Thu, 17 Oct 2024 19:26:24 +0200
Subject: [PATCH] clk: en7523: Fix wrong BUS clock for EN7581
The Documentation for EN7581 had a typo and still referenced the EN7523
BUS base source frequency. This was in conflict with a different page in
the Documentration that state that the BUS runs at 300MHz (600MHz source with
divisor set to 2) and the actual watchdog that tick at half the BUS
clock (150MHz). This was verified with the watchdog by timing the
seconds that the system takes to reboot (due too watchdog) and by
operating on different values of the BUS divisor.
The correct values for source of BUS clock are 600MHz and 540MHz.
This was also confirmed by Airoha.
Cc: stable@vger.kernel.org
Fixes: 66bc47326ce2 ("clk: en7523: Add EN7581 support")
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/clk-en7523.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -87,6 +87,7 @@ static const u32 slic_base[] = { 1000000
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
/* EN7581 */
static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
+static const u32 bus7581_base[] = { 600000000, 540000000 };
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
static const u32 crypto_base[] = { 540000000, 480000000 };
@@ -222,8 +223,8 @@ static const struct en_clk_desc en7581_b
.base_reg = REG_BUS_CLK_DIV_SEL,
.base_bits = 1,
.base_shift = 8,
- .base_values = bus_base,
- .n_base_values = ARRAY_SIZE(bus_base),
+ .base_values = bus7581_base,
+ .n_base_values = ARRAY_SIZE(bus7581_base),
.div_bits = 3,
.div_shift = 0,

View File

@ -0,0 +1,36 @@
From 38d2c6aafc5bbcad3ec36f6d3356b3debd40f6fd Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 16 Oct 2024 20:26:05 +0200
Subject: [RFC PATCH v2 1/3] spinlock: extend guard with spinlock_bh variants
Extend guard APIs with missing raw/spinlock_bh variants.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
include/linux/spinlock.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -515,6 +515,10 @@ DEFINE_LOCK_GUARD_1(raw_spinlock_irq, ra
raw_spin_lock_irq(_T->lock),
raw_spin_unlock_irq(_T->lock))
+DEFINE_LOCK_GUARD_1(raw_spinlock_bh, raw_spinlock_t,
+ raw_spin_lock_bh(_T->lock),
+ raw_spin_unlock_bh(_T->lock))
+
DEFINE_LOCK_GUARD_1(raw_spinlock_irqsave, raw_spinlock_t,
raw_spin_lock_irqsave(_T->lock, _T->flags),
raw_spin_unlock_irqrestore(_T->lock, _T->flags),
@@ -528,6 +532,10 @@ DEFINE_LOCK_GUARD_1(spinlock_irq, spinlo
spin_lock_irq(_T->lock),
spin_unlock_irq(_T->lock))
+DEFINE_LOCK_GUARD_1(spinlock_bh, spinlock_t,
+ spin_lock_bh(_T->lock),
+ spin_unlock_bh(_T->lock))
+
DEFINE_LOCK_GUARD_1(spinlock_irqsave, spinlock_t,
spin_lock_irqsave(_T->lock, _T->flags),
spin_unlock_irqrestore(_T->lock, _T->flags),

View File

@ -1,6 +1,6 @@
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -353,6 +353,12 @@ config SPI_DLN2
@@ -363,6 +363,12 @@ config SPI_DLN2
This driver can also be built as a module. If so, the module
will be called spi-dln2.
@ -15,7 +15,7 @@
depends on ARCH_EP93XX || COMPILE_TEST
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.
@@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o

View File

@ -0,0 +1,578 @@
--- /dev/null
+++ b/drivers/mtd/nand/airoha_bmt.c
@@ -0,0 +1,575 @@
+
+/*
+ * Airoha BMT algorithm
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include "mtk_bmt.h"
+
+#define MAX_BMT_SIZE (250)
+#define MAX_RAW_BAD_BLOCK_SIZE (250)
+#define POOL_GOOD_BLOCK_PERCENT 8/100
+#define MAX_BMT_PERCENT 1/8
+
+typedef struct {
+ char signature[3];
+ u8 version;
+ u8 bad_count; // this field is useless
+ u8 size;
+ u8 checksum;
+ u8 reseverd[13];
+} bmt_table_header;
+
+typedef struct {
+ u16 from;
+ u16 to;
+} bmt_entry;
+
+typedef struct {
+ bmt_table_header header;
+ bmt_entry table[MAX_BMT_SIZE];
+} bmt_table;
+
+typedef struct {
+ char signature[4];
+ u32 checksum;
+ u8 version;
+ u8 size;
+ u8 reserved[2];
+} bbt_table_header;
+
+typedef struct {
+ bbt_table_header header;
+ u16 table[MAX_RAW_BAD_BLOCK_SIZE];
+} bbt_table;
+
+bbt_table bbt;
+bmt_table bmt;
+
+int bmt_index=0xffff;
+int bbt_index=0xffff;
+unsigned int total_blks , system_blks , bmt_blks, _to, _to2, val;
+
+module_param(bmt_index, int, S_IRUSR | S_IWUSR);
+module_param(bbt_index, int, S_IRUSR | S_IWUSR);
+module_param(total_blks, int, S_IRUSR | S_IWUSR);
+module_param(system_blks, int, S_IRUSR | S_IWUSR);
+module_param(bmt_blks, int, S_IRUSR | S_IWUSR);
+module_param(_to, int, S_IRUSR | S_IWUSR);
+module_param(_to2, int, S_IRUSR | S_IWUSR);
+module_param(val, int, S_IRUSR | S_IWUSR);
+
+
+static bool is_bad_raw(int block) {
+ u8 fdm[4];
+ int ret;
+ ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size,
+ fdm, sizeof(fdm));
+ if (ret || fdm[0] != 0xff ){
+ return true;
+ }
+ return false;
+}
+
+static bool is_bad( int block) {
+ u8 fdm[4];
+ int ret;
+ ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size,
+ fdm, sizeof(fdm));
+ //printk("%x %x %x %x\n", fdm[0], fdm[1], fdm[2], fdm[3]);
+ if (ret || fdm[0] != 0xff || fdm[1] != 0xff ){
+ return true;
+ }
+ return false;
+}
+
+
+static bool is_mapped( int block) {
+ u16 mapped_block;
+ u8 fdm[4];
+ int ret;
+
+ ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size,
+ fdm, sizeof(fdm));
+ mapped_block = (fdm[2] << 8) | fdm[3];
+ //printk("%u is mapped to %d\n", mapped_block);
+ if (mapped_block == 0xffff)
+ return false;
+ else return true;
+}
+
+static void mark_bad(int block) {
+ u8 fdm[4] = {0xff, 0xff, 0xff, 0xff};
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 4,
+ .oobbuf = fdm,
+ .datbuf = NULL,
+ .len = 0,
+ };
+ int retlen;
+
+ printk("marking bad :%d\n", block);
+ if (block < system_blks)
+ fdm[0] = 0x00;
+ else fdm[1] = 0x00;
+
+ retlen = bmtd._write_oob(bmtd.mtd, block << bmtd.blk_shift , &ops) ;
+ if (retlen < 0) {
+ printk("marking bad block failed \n");
+ }
+}
+
+
+static void mark_good(int block) {
+ u8 fdm[4] = {0xff, 0xff, 0xff, 0xff};
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 4,
+ .oobbuf = fdm,
+ .datbuf = NULL,
+ .len = 0,
+ };
+ int retlen;
+ retlen = bmtd._write_oob(bmtd.mtd, block << bmtd.blk_shift , &ops) ;
+ if (retlen < 0) {
+ printk("marking bad block failed \n");
+ }
+}
+
+static void make_mapping(u16 from , u16 to) {
+ u8 fdm[4] = {0xff, 0xff, 0xff , 0xff};
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 4,
+ .oobbuf = fdm,
+ .datbuf = NULL,
+ .len = 0,
+ };
+ int retlen;
+
+ memcpy(fdm + 2, &to, sizeof(to)); // this has to be exactly like this .
+ retlen = bmtd._write_oob(bmtd.mtd, from << bmtd.blk_shift , &ops) ;
+ if (retlen < 0) {
+ printk("marking bad block failed \n");
+ }
+}
+
+static u16 bbt_checksum(void) {
+ int i=0;
+ u16 checksum =0;
+ u8 *data = (u8*) &bbt;
+ checksum += bbt.header.version;
+ checksum += bbt.header.size;
+ data += sizeof(bbt_table_header);
+ for (; i < sizeof(bbt.table); i++)
+ checksum += data[i];
+ return checksum;
+}
+
+static bool parse_bbt(void) {
+ int i = system_blks;
+ u8 fdm[4];
+ for (; i < total_blks; i++) {
+ if( !is_bad(i)
+ && !bbt_nand_read(blk_pg(i),(unsigned char *)&bbt, sizeof(bbt), fdm, sizeof(fdm))
+ && (strncmp(bbt.header.signature , "RAWB", 4)==0)
+ && (bbt.header.checksum == bbt_checksum())
+ ) {
+ bbt_index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+static u8 bmt_checksum(void) {
+ int i;
+ u8 checksum = 0;
+ u8* data = (u8*)&bmt;
+ checksum += bmt.header.version;
+ checksum += bmt.header.size;
+ data += sizeof(bmt_table_header);
+ for (i=0;i<bmt_blks*sizeof(bmt_entry);i++)
+ checksum += data[i];
+ return checksum;
+}
+
+static bool parse_bmt(void) {
+ int i = total_blks-1 ;
+ u8 fdm[4];
+ for (; i> system_blks;i--) {
+ if ( !is_bad(i)
+ && !bbt_nand_read(blk_pg(i),(unsigned char *)&bmt, sizeof(bmt), fdm, sizeof(fdm))
+ && (strncmp(bmt.header.signature , "BMT", 3)==0)
+ && (bmt.header.checksum == bmt_checksum())
+ ) {
+ bmt_index = i ;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void variable_setup(void) {
+ unsigned int need_valid_block_num;
+ int valid_blks = 0;
+ int last_blk;
+
+ total_blks = bmtd.total_blks;
+ last_blk = total_blks - 1;
+ need_valid_block_num = total_blks * POOL_GOOD_BLOCK_PERCENT;
+
+ for (; last_blk > 0 ;last_blk--) {
+ if (is_bad_raw(last_blk)) {
+ continue;
+ }
+ valid_blks++;
+ if (valid_blks == need_valid_block_num) {
+ break;
+ }
+ }
+ bmt_blks = total_blks - last_blk;
+ system_blks = total_blks - bmt_blks;
+ bmtd.mtd->size = (total_blks - total_blks * MAX_BMT_PERCENT) * bmtd.mtd->erasesize;
+}
+
+
+static int find_available_block(bool start_from_end) {
+ int i=system_blks,d=1;
+ int count = 0;
+ if (start_from_end)
+ i=total_blks-1,d=-1;
+ for (; count < (total_blks - system_blks); count++, i+=d) {
+ if(bmt_index == i || bbt_index == i || is_bad(i) || is_mapped(i))
+ continue;
+ return i ;
+ }
+ //TODO: handle OOM
+ return -1;
+}
+
+static void update_bmt_bbt( void ) {
+ int retlen = 0;
+ struct mtd_oob_ops ops , ops1;
+
+ bbt.header.checksum = bbt_checksum();
+ bmt.header.checksum = bmt_checksum();
+
+ if(bbt_index ==0xffff) bbt_index = find_available_block(false);
+ if(bmt_index ==0xffff) bmt_index = find_available_block(true);
+
+ bbt_nand_erase(bmt_index);
+ bbt_nand_erase(bbt_index);
+ printk("putting back in bbt_index: %d, bmt_index: %d\n" , bbt_index, bmt_index);
+
+ ops = (struct mtd_oob_ops) {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ .len = sizeof(bmt),
+ .datbuf = (u8 *)&bmt,
+ };
+
+retry_bmt:
+ retlen = bmtd._write_oob(bmtd.mtd, bmt_index << bmtd.blk_shift, &ops);
+ if (retlen) {
+ printk("error while write");
+ mark_bad(bmt_index);
+ if (bmt_index > system_blks) {
+ bmt_index--;
+ goto retry_bmt;
+ }
+ return;
+ }
+ ops1 = (struct mtd_oob_ops) {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ .len = sizeof(bbt),
+ .datbuf = (u8 *)&bbt,
+ };
+
+retry_bbt:
+ retlen = bmtd._write_oob(bmtd.mtd, bbt_index << bmtd.blk_shift, &ops1);
+ if (retlen) {
+ printk("error while write");
+ mark_bad(bbt_index);
+ if (bbt_index < total_blks) {
+ bbt_index++;
+ goto retry_bbt;
+ }
+ return;
+ }
+}
+
+static bool is_in_bmt(int block) {
+ int i;
+ for (i=0;i<bmt.header.size;i++)
+ if (bmt.table[i].from == block)
+ return true;
+ return false;
+}
+
+static void reconstruct_from_oob(void) {
+ int i;
+
+ memset(&bmt,0x00,sizeof(bmt));
+ memcpy(&bmt.header.signature, "BMT",3);
+ bmt.header.version = 1;
+ bmt.header.size = 0;
+ for ( i = total_blks -1 ; i >= system_blks ;i--) {
+ unsigned short mapped_block;
+ u8 fdm[4];
+ int ret;
+
+ if (is_bad(i)) continue;
+ ret = bbt_nand_read(blk_pg(i), bmtd.data_buf, bmtd.pg_size,
+ fdm, sizeof(fdm));
+ if (ret < 0)
+ mark_bad(i);
+
+ memcpy(&mapped_block,fdm+2,2); // need to be this way
+ if (mapped_block >= system_blks) continue;
+ printk("block %X was mapped to :%X\n", mapped_block, i);
+ bmt.table[bmt.header.size++] = (bmt_entry){.from = mapped_block , .to = i};
+ }
+ memset(&bbt,0x00,sizeof(bbt));
+ memcpy(&bbt.header.signature , "RAWB", 4);
+ bbt.header.version = 1;
+ bbt.header.size = 0;
+ for ( i = 0 ; i < system_blks; i++) {
+ if (is_bad_raw(i) && !is_in_bmt(i))
+ bbt.table[bbt.header.size++] = (u16)i;
+ }
+ bmt.header.checksum = bmt_checksum();
+ bbt.header.checksum = bbt_checksum();
+ update_bmt_bbt();
+ printk("bbt and bmt reconstructed successfully\n");
+}
+
+
+static bool remap_block(u16 block , u16 mapped_block, int copy_len) {
+ bool mapped_already_in_bbt = false;
+ bool mapped_already_in_bmt = false;
+ bool block_already_in_bbt = false;
+ u16 new_block = find_available_block(false);
+ int i;
+ // TODO check for -1
+
+ bbt_nand_erase(new_block);
+ if (copy_len)
+ bbt_nand_copy(new_block , mapped_block , copy_len);
+
+ for (i=0; i < bmt.header.size; i++)
+ if (bmt.table[i].from == block) {
+ bmt.table[i].to = new_block;
+ mapped_already_in_bmt = true;
+ break;
+ }
+
+ if (!mapped_already_in_bmt)
+ bmt.table[bmt.header.size++] = (bmt_entry){ .from = block, .to = new_block};
+
+ for (i=0;i<bbt.header.size;i++)
+ if (bbt.table[i] == mapped_block) {
+ mapped_already_in_bbt = true;
+ break;
+ } else if (bbt.table[i] == block) {
+ block_already_in_bbt = true;
+ break;
+ }
+
+ if (!mapped_already_in_bbt)
+ bbt.table[bbt.header.size++] = mapped_block;
+ if (mapped_block != block && !block_already_in_bbt)
+ bbt.table[bbt.header.size++] = block;
+
+ if (mapped_block != block) mark_bad(mapped_block);
+ mark_bad(block);
+ make_mapping(new_block, block);
+
+ update_bmt_bbt();
+ return false;
+}
+
+static int init(struct device_node *np) {
+ variable_setup();
+ if (!(parse_bbt() && parse_bmt())) {
+ reconstruct_from_oob();
+ } else {
+ printk("bmt/bbt found\n");
+ }
+ return 0;
+}
+
+static int get_mapping_block( int block) {
+ int i;
+
+ if (block > system_blks)
+ return block;
+ for (i = 0; i < bmt.header.size; i++)
+ if (bmt.table[i].from == block)
+ return bmt.table[i].to;
+ return block;
+}
+
+static void unmap_block( u16 block) { // not required
+ printk("unmapping is called on block : %d\n", block);
+}
+
+
+static int debug( void* data , u64 cmd) {
+ int i;
+ printk("val: %d\n", val);
+ printk("_to: %d\n", _to);
+ if (val == 0 ) {
+ printk("fixing all\n");
+ for (i=0;i<total_blks;i++) {
+ mark_good(i);
+ }
+ } else if(val ==1 ) {
+ int mapped_block;
+ printk("remapping: %d\n", _to);
+ mapped_block = get_mapping_block(_to);
+ printk("before mapped to: %d\n", mapped_block);
+ remap_block(_to , mapped_block, bmtd.mtd->erasesize);
+ mapped_block = get_mapping_block(_to);
+ printk("after mapped to: %d\n", mapped_block);
+ } else if(val ==2 ) {
+ printk("bmt table: \n");
+ for (i = 0 ; i < bmt.header.size;i++) {
+ printk("%d->%d\n", bmt.table[i].from , bmt.table[i].to);
+ }
+ printk("bbt table\n");
+ for (i =0;i< bbt.header.size;i++) {
+ printk("%d ", bbt.table[i]);
+ }
+ printk("\n");
+ } else if(val == 3) {
+ printk("reconstruct from oob\n");
+ reconstruct_from_oob();
+ } else if (val == 4) {
+ printk("showing the oobreconstruct_from_oob of %d\n", _to);
+ printk("%d\n",is_bad(_to));
+ } else if (val == 5 ) {
+ printk("trying to parse_bmt again %d\n", parse_bmt());
+ } else if (val == 6 ) {
+ printk("marking bad : %d", _to);
+ mark_bad(_to);
+ } else if ( val == 7) {
+ struct mtd_oob_ops opsk = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ .len = sizeof(bmt),
+ .datbuf = (u8 *)&bmt,
+ };
+ int retlen;
+ printk("parse bmt from the %d block \n", _to);
+ retlen = bmtd._read_oob(bmtd.mtd, _to << bmtd.blk_shift , &opsk);
+
+ printk("status : %d\n", retlen);
+ } else if (val == 8) {
+ u8 *data;
+ int j;
+ printk("dump bmt hex\n");
+ data = (u8 *)&bmt;
+ for (j =0;j < 50;j++) {
+ if(j%20==0) printk("\n");
+ printk("%X ", data[j]);
+ }
+ printk("bbt table\n");
+ data = (u8 *)&bbt;
+ for (j =0;j < 50;j++) {
+ if(j%20==0) printk("\n");
+ printk("%X ", data[j]);
+ }
+ } else if (val == 9) {
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ .len = sizeof(bmt),
+ .datbuf = (u8 *)&bmt,
+ };
+ int retlen;
+ printk("put bmt at index\n");
+ retlen = bmtd._write_oob(bmtd.mtd, _to << bmtd.blk_shift, &ops);
+ bmt.header.checksum = bmt_checksum();
+ if (retlen < 0) {
+ printk("error while write");
+ }
+ } else if (val == 10) {
+ printk("erase block %d\n", _to);
+ bbt_nand_erase(_to);
+ } else if (val == 11) {
+ char *buf1, *buf2;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ };
+ struct mtd_oob_ops ops1 = {
+ .mode = MTD_OPS_PLACE_OOB,
+ .ooboffs = 0,
+ .ooblen = 0,
+ .oobbuf = NULL,
+ };
+ int retlen;
+ int j;
+
+ printk("tranfering content from block :%d to %d\n", _to , _to2);
+ bbt_nand_copy(_to2, _to, bmtd.mtd->erasesize);
+ printk("now we check size\n");
+
+ buf1 = (char*) kzalloc(sizeof(char) * bmtd.mtd->erasesize , GFP_KERNEL);
+ buf2 = (char*) kzalloc(sizeof(char) * bmtd.mtd->erasesize , GFP_KERNEL);
+
+ ops.len = sizeof(char) * bmtd.mtd->erasesize;
+ ops.datbuf = buf1;
+ retlen = bmtd._read_oob(bmtd.mtd, _to << bmtd.blk_shift, &ops);
+ if (retlen < 0) {
+ printk("error while write\n");
+ }
+
+ ops1.len = sizeof(char) * bmtd.mtd->erasesize;
+ ops1.datbuf = buf2;
+ retlen = bmtd._read_oob(bmtd.mtd, _to << bmtd.blk_shift, &ops1);
+ if (retlen < 0) {
+ printk("error while write");
+ }
+ for (j = 0 ; j < bmtd.mtd->erasesize ;j++) {
+ if (j%20==0) {
+ printk("\n");
+ }
+ printk("%X %X ", buf1[j], buf2[j]);
+ }
+ printk("\n");
+
+ }
+ return 0;
+}
+
+
+const struct mtk_bmt_ops airoha_bmt_ops = {
+ .sig = "bmt",
+ .sig_len = 3,
+ .init = init,
+ .remap_block = remap_block,
+ .unmap_block = unmap_block,
+ .get_mapping_block = get_mapping_block,
+ .debug = debug,
+};

View File

@ -0,0 +1,34 @@
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
+#include <linux/mtd/mtk_bmt.h>
static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
{
@@ -1346,6 +1347,7 @@ static int spinand_probe(struct spi_mem
if (ret)
return ret;
+ mtk_bmt_attach(mtd);
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto err_spinand_cleanup;
@@ -1353,6 +1355,7 @@ static int spinand_probe(struct spi_mem
return 0;
err_spinand_cleanup:
+ mtk_bmt_detach(mtd);
spinand_cleanup(spinand);
return ret;
@@ -1371,6 +1374,7 @@ static int spinand_remove(struct spi_mem
if (ret)
return ret;
+ mtk_bmt_detach(mtd);
spinand_cleanup(spinand);
return 0;

View File

@ -0,0 +1,170 @@
From ca46c5834ba3a74595a93d7a491fa9c943be7c30 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Sun, 28 Jul 2024 12:15:53 +0200
Subject: [PATCH 3/3] mtd: parser: add support for Airoha parser
Add support for Airoha parser based on a post parse ofpart function.
Airoha partition table follow normal fixed-partition implementation
with a special implementation for the ART partition. This is always the
past partition and is placed from the end of the flash - the partition
size.
To enable this special implementation for ART partition, the relevant
node require the "airoha,dynamic-art" compatible. With that declared,
offset value is ignored and real offset is updated with the calculated
value.
Due to usage of specific bad block management driver, the MTD size might
vary hence the ART partition offset needs to be dynamically parsed and
can't be declared statically.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/mtd/parsers/Kconfig | 10 ++++++
drivers/mtd/parsers/Makefile | 1 +
drivers/mtd/parsers/ofpart_airoha.c | 56 +++++++++++++++++++++++++++++
drivers/mtd/parsers/ofpart_airoha.h | 18 ++++++++++
drivers/mtd/parsers/ofpart_core.c | 6 ++++
5 files changed, 91 insertions(+)
create mode 100644 drivers/mtd/parsers/ofpart_airoha.c
create mode 100644 drivers/mtd/parsers/ofpart_airoha.h
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -93,6 +93,16 @@ config MTD_OF_PARTS
flash memory node, as described in
Documentation/devicetree/bindings/mtd/mtd.yaml.
+config MTD_OF_PARTS_AIROHA
+ bool "Airoha EN7815 partitioning support"
+ depends on MTD_OF_PARTS && (ARCH_AIROHA || COMPILE_TEST)
+ default ARCH_AIROHA
+ help
+ This provides partitions parser for Airoha EN7815 family devices
+ that can have dynamic "ART" partition at the end of the flash.
+ It takes care of finding the correct offset and update property
+ with it.
+
config MTD_OF_PARTS_BCM4908
bool "BCM4908 partitioning support"
depends on MTD_OF_PARTS && (ARCH_BCMBCA || COMPILE_TEST)
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdl
obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
ofpart-y += ofpart_core.o
+ofpart-$(CONFIG_MTD_OF_PARTS_AIROHA) += ofpart_airoha.o
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
--- /dev/null
+++ b/drivers/mtd/parsers/ofpart_airoha.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include "ofpart_airoha.h"
+
+int airoha_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts)
+{
+ struct mtd_partition *part;
+ int len, a_cells, s_cells;
+ struct device_node *pp;
+ struct property *prop;
+ const __be32 *reg;
+ __be32 *new_reg;
+
+ part = &parts[nr_parts - 1];
+ pp = part->of_node;
+
+ /* Skip if ART partition have a valid offset instead of a dynamic one */
+ if (!of_device_is_compatible(pp, "airoha,dynamic-art"))
+ return 0;
+
+ /* ART partition is set at the end of flash - size */
+ part->offset = mtd->size - part->size;
+
+ /* Update the offset with the new calculate value in DT */
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+
+ /* Reg already validated by fixed-partition parser */
+ reg = of_get_property(pp, "reg", &len);
+
+ /* Fixed partition */
+ a_cells = of_n_addr_cells(pp);
+ s_cells = of_n_size_cells(pp);
+
+ prop->name = "reg";
+ prop->length = (a_cells + s_cells) * sizeof(__be32);
+ prop->value = kmemdup(reg, (a_cells + s_cells) * sizeof(__be32),
+ GFP_KERNEL);
+ new_reg = prop->value;
+ memset(new_reg, 0, a_cells * sizeof(__be32));
+ new_reg[a_cells - 1] = cpu_to_be32(part->offset);
+ if (a_cells > 1)
+ new_reg[0] = cpu_to_be32(part->offset >> 32);
+ of_update_property(pp, prop);
+
+ return 0;
+}
--- /dev/null
+++ b/drivers/mtd/parsers/ofpart_airoha.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __OFPART_AIROHA_H
+#define __OFPART_AIROHA_H
+
+#ifdef CONFIG_MTD_OF_PARTS_AIROHA
+int airoha_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts);
+#else
+static inline int airoha_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#endif
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/mtd/partitions.h>
+#include "ofpart_airoha.h"
#include "ofpart_bcm4908.h"
#include "ofpart_linksys_ns.h"
@@ -23,6 +24,10 @@ struct fixed_partitions_quirks {
int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
};
+static struct fixed_partitions_quirks airoha_partitions_quirks = {
+ .post_parse = airoha_partitions_post_parse,
+};
+
static struct fixed_partitions_quirks bcm4908_partitions_quirks = {
.post_parse = bcm4908_partitions_post_parse,
};
@@ -192,6 +197,7 @@ static const struct of_device_id parse_o
/* Generic */
{ .compatible = "fixed-partitions" },
/* Customized */
+ { .compatible = "airoha,fixed-partitions", .data = &airoha_partitions_quirks, },
{ .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
{ .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, },
{},