siflower: new target for Siflower SF19A2890

Siflower SF19A2890 is an SoC with:
Dual-core MIPS InterAptiv at 800MHz
DDR3 controller
One Gigabit Ethernet MAC with RGMII and IPv4 HNAT engine
Built-in 2x2 11N + 2x2 11AC WiFi radio
USB 2.0 OTG
I2C/SPI/GPIO and various other peripherals

This adds support for SF19A2890 EVB with ethernet support.

EVB spec:
Memory: DDR3 128M
Ethernet: RTL8367RB 5-port gigabit switch
Flash: 16M NOR
Others: MicroUSB OTG, LED x 1, Reset button x1

The built image can be flashed using u-boot recovery.

This target is marked as source-only until support for a commercial
router board comes.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
This commit is contained in:
Chuanhong Guo 2024-08-08 12:56:03 +08:00
parent a5d881f3a3
commit 0dc62d9d8b
31 changed files with 3557 additions and 0 deletions

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-only
include $(TOPDIR)/rules.mk
ARCH:=mipsel
BOARD:=siflower
BOARDNAME:=Siflower SoCs
FEATURES:=squashfs usb usbgadget source-only
SUBTARGETS:=sf19a2890
KERNEL_PATCHVER:=6.6
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES += \
kmod-gpio-button-hotplug \
uboot-envtools
$(eval $(call BuildTarget))

View File

@ -0,0 +1,651 @@
#include <dt-bindings/clock/siflower,sf19a2890-clk.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/mips-gic.h>
/ {
compatible = "siflower,sf19a2890";
#address-cells = <1>;
#size-cells = <1>;
aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
chosen {
bootargs = "earlycon";
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
wlan24_dsp: wlandsp@1f00000 {
reg = <0x01f00000 0x200000>;
};
wlan5_dsp: wlandsp@2100000 {
reg = <0x02100000 0x200000>;
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "mti,interaptiv";
reg = <0>;
clocks = <&clk CLK_MUXDIV_CPU>;
clock-names = "cpu";
clock-latency = <0>;
};
cpu@1 {
device_type = "cpu";
compatible = "mti,interaptiv";
reg = <1>;
clocks = <&clk CLK_MUXDIV_CPU>;
clock-names = "cpu";
clock-latency = <0>;
};
cpu@2 {
device_type = "cpu";
compatible = "mti,interaptiv";
reg = <2>;
clocks = <&clk CLK_MUXDIV_CPU>;
clock-names = "cpu";
clock-latency = <0>;
};
cpu@3 {
device_type = "cpu";
compatible = "mti,interaptiv";
reg = <3>;
clocks = <&clk CLK_MUXDIV_CPU>;
clock-names = "cpu";
clock-latency = <0>;
};
};
osc32k: oscillator-32k {
compatible = "fixed-clock";
clock-frequency = <32768>;
#clock-cells = <0>;
clock-output-names = "osc32k";
};
osc12m: oscillator-12m {
compatible = "fixed-clock";
clock-frequency = <12000000>;
#clock-cells = <0>;
clock-output-names = "osc12m";
};
osc40m: oscillator-40m {
compatible = "fixed-clock";
clock-frequency = <40000000>;
#clock-cells = <0>;
clock-output-names = "osc40m";
};
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;
interrupt-parent = <&gic>;
gmac: ethernet@10800000 {
compatible = "siflower,sf19a2890-gmac", "snps,dwmac";
reg = <0x10800000 0x200000>,
<0x19e04440 0x10>;
interrupts = <GIC_SHARED 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SHARED 34 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SHARED 33 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
clocks = <&gmacclk 0>, <&gmacclk 1>, <&gmacclk 3>, <&gmacclk 2>;
clock-names = "stmmaceth", "pclk", "ptp_ref", "gmac_byp_ref";
resets = <&gmacrst 0>;
reset-names = "stmmaceth";
pinctrl-names = "default";
pinctrl-0 = <&rgmii_pins>, <&mdio_pins>;
status = "disabled";
mdio: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
};
};
wlan_rf: phy@11c00000{
compatible = "siflower,sf19a2890-rf";
reg = <0x11c00000 0x600000>;
interrupts = <GIC_SHARED 187 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rfclk 1>, <&rfclk 2>, <&rfclk 3>;
clock-names = "axi", "boot", "lp";
resets = <&rfrst 0>;
pinctrl-names = "default";
pinctrl-0 = <&wlan_pins>;
status = "disabled";
};
usb: usb@17000000 {
compatible = "siflower,sf19a2890-usb";
reg = <0x17000000 0x40000>;
interrupts = <GIC_SHARED 128 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&usbclk 0>;
clock-names = "otg";
resets = <&usbrst 0>;
reset-names = "dwc2";
dr_mode = "otg";
phys = <&usb_phy>;
phy-names = "usb2-phy";
g-np-tx-fifo-size = <768>;
status = "disabled";
};
i2c: i2c@18100000 {
compatible = "snps,designware-i2c";
reg = <0x18100000 0x1000>;
interrupts = <GIC_SHARED 217 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&i2cclk 0>;
clock-names = "ref";
resets = <&i2crst 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
};
spi: spi@18202000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0x18202000 0x1000>;
cs-gpios = <&gpio 8 GPIO_ACTIVE_LOW>;
clocks = <&spiclk 1>, <&spiclk 0>;
clock-names = "sspclk", "apb_pclk";
interrupts = <GIC_SHARED 225 IRQ_TYPE_LEVEL_HIGH>;
resets = <&spirst 0>;
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&spi_pins>;
status = "disabled";
};
uart0: serial@18300000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x18300000 0x1000>;
interrupts = <GIC_SHARED 226 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uartclk 3>, <&uartclk 0>;
clock-names = "uartclk", "apb_pclk";
resets = <&uartrst 0>;
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins>;
status = "disabled";
};
uart1: serial@18301000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x18301000 0x1000>;
interrupts = <GIC_SHARED 227 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uartclk 4>, <&uartclk 1>;
clock-names = "uartclk", "apb_pclk";
resets = <&uartrst 1>;
pinctrl-names = "default";
pinctrl-0 = <&uart1_pins>;
status = "disabled";
};
uart2: serial@18302000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x18302000 0x1000>;
interrupts = <GIC_SHARED 228 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uartclk 5>, <&uartclk 2>;
clock-names = "uartclk", "apb_pclk";
resets = <&uartrst 2>;
pinctrl-names = "default";
pinctrl-0 = <&uart2_pins>;
status = "disabled";
};
watchdog: watchdog@18700000 {
compatible = "snps,dw-wdt";
reg = <0x18700000 0x1000>;
interrupts = <GIC_SHARED 238 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&wdtclk 0>;
resets = <&wdtrst 0>;
};
gpio: gpio@19d00000 {
compatible = "siflower,sf19a2890-gpio";
reg=<0x19d00000 0x100000>;
interrupts = <GIC_SHARED 246 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SHARED 247 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SHARED 248 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SHARED 249 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gpioclk 0>;
resets = <&gpiorst 0>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 49>;
interrupt-controller;
#interrupt-cells = <2>;
};
clk: clock-controller@19e01000 {
compatible = "siflower,sf19a2890-clk";
reg = <0x19e01000 0x800>;
clocks = <&osc12m>, <&osc40m>;
clock-names = "osc12m", "osc40m";
#clock-cells = <1>;
};
brom_sysm: syscon@19e02000 {
compatible = "syscon", "simple-mfd";
reg = <0x19e02000 0x100>;
reboot {
compatible = "syscon-reboot";
offset = <0x30>;
value = <0x1>;
};
};
gmacrst: reset-controller@19e04400 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e04400 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x3>;
};
gmacclk: clock-controller@19e04404 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e04404 0xc>;
clocks = <&clk CLK_MUXDIV_BUS1>, <&clk CLK_MUXDIV_CPU>, <&clk CLK_MUXDIV_GMAC_BYP_REF>, <&clk CLK_MUXDIV_ETH_TSU>;
clock-output-names = "gmac", "gmac_pclk", "gmac_byp_ref", "ethtsu";
#clock-cells = <1>;
};
wlan24rst: reset-controller@19e08000 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e08000 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x7>;
};
wlan24clk: clock-controller@19e08004 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e08004 0xc>;
clocks = <&clk CLK_MUXDIV_CPU>, <&clk CLK_MUXDIV_BUS2>, <&clk CLK_MUXDIV_WLAN24_PLF>;
clock-output-names = "wlan24_axis", "wlan24_axim", "wlan24_plf";
#clock-cells = <1>;
};
rfrst: reset-controller@19e08800 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e08800 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x7>;
};
rfclk: clock-controller@19e08804 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e08804 0xc>;
clocks = <&clk CLK_MUXDIV_BUS2>, <&clk CLK_MUXDIV_CPU>, <&osc12m>, <&osc32k>;
clock-output-names = "rf_dft", "rf_axis", "rf_boot", "rf_lp";
#clock-cells = <1>;
};
usbrst: reset-controller@19e0c000 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e0c000 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x7 0x8 0x10>;
};
usbclk: clock-controller@19e0c004 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e0c004 0xc>;
clocks = <&clk CLK_MUXDIV_BUS3>, <&clk CLK_MUXDIV_CPU>, <&clk CLK_MUXDIV_USBPHY_REF>;
clock-output-names = "usb", "usb_axim", "usbphy_ref";
siflower,valid-gates = <0xd>;
siflower,critical-gates = <0x4>;
#clock-cells = <1>;
};
usb_phy: usb-phy@19e0c040 {
compatible = "siflower,sf19a2890-usb-phy";
reg = <0x19e0C040 0x60>;
clocks = <&usbclk 2>;
resets = <&usbrst 1>, <&usbrst 2>;
reset-names = "power_on_rst", "usb_phy_rst";
#phy-cells = <0>;
status = "disabled";
};
wlan5rst: reset-controller@19e0c400 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e0c400 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x7>;
};
wlan5clk: clock-controller@19e0c404 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e0c404 0xc>;
clocks = <&clk CLK_MUXDIV_CPU>, <&clk CLK_MUXDIV_BUS2>, <&clk CLK_MUXDIV_WLAN5_PLF>;
clock-output-names = "wlan5_axis", "wlan5_axim", "wlan5_plf";
#clock-cells = <1>;
};
i2crst: reset-controller@19e24400 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e24400 0x4>;
#reset-cells = <1>;
siflower,num-resets = <1>;
};
i2cclk: clock-controller@19e24404 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e24404 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "i2c0";
#clock-cells = <1>;
};
spirst: reset-controller@19e24800 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e24800 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x30>;
};
spiclk: clock-controller@19e24804 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e24804 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>, <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "spi_apb", "spi_ssp";
siflower,valid-gates = <0x30>;
#clock-cells = <1>;
};
uartrst: reset-controller@19e24c00 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e24c00 0x4>;
#reset-cells = <1>;
siflower,reset-masks = <0x11 0x22 0x44>;
};
uartclk: clock-controller@19e24c04 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e24c04 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>, <&clk CLK_MUXDIV_PBUS>, <&clk CLK_MUXDIV_PBUS>,
<&clk CLK_MUXDIV_UART>, <&clk CLK_MUXDIV_UART>, <&clk CLK_MUXDIV_UART>;
clock-output-names = "uart0_apb", "uart1_apb", "uart2_apb",
"uart0", "uart1","uart2";
siflower,valid-gates = <0x77>;
siflower,critical-gates = <0x11>;
#clock-cells = <1>;
};
pwmrst: reset-controller@19e25400 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e25400 0x4>;
#reset-cells = <1>;
siflower,num-resets = <1>;
};
pwmclk: clock-controller@19e25404 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e25404 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "pwm";
#clock-cells = <1>;
};
timerrst: reset-controller@19e25800 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e25800 0x4>;
#reset-cells = <1>;
siflower,num-resets = <1>;
};
timerclk: clock-controller@19e25804 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e25804 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "timer";
#clock-cells = <1>;
};
wdtrst: reset-controller@19e25c00 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e25c00 0x4>;
#reset-cells = <1>;
siflower,num-resets = <1>;
};
wdtclk: clock-controller@19e25c04 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e25c04 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "wdt";
#clock-cells = <1>;
};
gpiorst: reset-controller@19e2b400 {
compatible = "siflower,sf19a2890-periph-reset";
reg = <0x19e2b400 0x4>;
#reset-cells = <1>;
siflower,num-resets = <1>;
};
gpioclk: clock-controller@19e2b404 {
compatible = "siflower,sf19a2890-periph-clk";
reg = <0x19e2b404 0xc>;
clocks = <&clk CLK_MUXDIV_PBUS>;
clock-output-names = "gpio";
#clock-cells = <1>;
};
pinctrl: pinctrl@19e3fc00 {
compatible = "siflower,sf19a2890-pinctrl";
reg = <0x19e3fc00 0x400>;
jtag_pins: jtag-pins {
tdo {
pins = "JTAG_TDO";
function = "func0";
bias-disable;
};
input-pins {
pins = "JTAG_TDI", "JTAG_TMS", "JTAG_TCK";
function = "func0";
input-enable;
bias-disable;
};
trst {
pins = "JTAG_RST";
function = "func0";
input-enable;
bias-pull-down;
};
};
spi_pins: spi-pins {
sck {
pins = "SPI_CLK";
function = "func0";
bias-disable;
};
mosi {
pins = "SPI_TXD";
function = "func0";
bias-pull-down;
};
miso {
pins = "SPI_RXD";
function = "func0";
input-enable;
bias-pull-down;
};
cs {
pins = "SPI_CSN";
bias-pull-up;
};
};
uart0_pins: uart0-pins {
tx {
pins = "UART_TX";
function = "func0";
bias-pull-up;
};
rx {
pins = "UART_RX";
function = "func0";
input-enable;
bias-pull-up;
};
};
uart0_rtscts: uart0-rtscts-pins {
cts {
pins = "I2C_DAT";
function = "func0";
input-enable;
bias-pull-up;
};
rts {
pins = "I2C_CLK";
function = "func0";
bias-pull-up;
};
};
uart1_pins: uart1-pins {
tx {
pins = "JATG_TDO";
function = "func1";
bias-pull-up;
};
rx {
pins = "JATG_TDI";
function = "func1";
input-enable;
bias-pull-up;
};
};
uart1_rtscts: uart1-rtscts-pins {
cts {
pins = "JTAG_TMS";
function = "func1";
input-enable;
bias-pull-up;
};
rts {
pins = "JTAG_TCK";
function = "func1";
bias-pull-up;
};
};
uart2_pins: uart2-pins {
tx {
pins = "I2C_DAT";
function = "func1";
bias-pull-up;
};
rx {
pins = "I2C_CLK";
function = "func1";
input-enable;
bias-pull-up;
};
};
rgmii_pins: rgmii-pins {
tx-pins {
pins = "RGMII_TXCLK", "RGMII_TXD0",
"RGMII_TXD1", "RGMII_TXD2",
"RGMII_TXD3", "RGMII_TXCTL";
function = "func0";
bias-disable;
};
rx-pins {
pins = "RGMII_RXCLK", "RGMII_RXD0",
"RGMII_RXD1", "RGMII_RXD2",
"RGMII_RXD3", "RGMII_RXCTL";
function = "func0";
input-enable;
bias-disable;
};
};
mdio_pins: mdio-pins {
pins {
pins = "RGMII_MDC", "RGMII_MDIO";
function = "func0";
input-enable;
bias-pull-up;
};
};
wlan_pins: wlan-pins {
pins {
pins = "HB0_PA_EN", "HB0_LNA_EN",
"HB0_SW_CTRL0", "HB0_SW_CTRL1",
"HB1_PA_EN", "HB1_LNA_EN",
"HB1_SW_CTRL0", "HB1_SW_CTRL1",
"LB0_PA_EN", "LB0_LNA_EN",
"LB0_SW_CTRL0", "LB0_SW_CTRL1",
"LB1_PA_EN", "LB1_LNA_EN",
"LB1_SW_CTRL0", "LB1_SW_CTRL1";
function = "func0";
};
};
i2c0_pins: i2c0-pins {
pins {
pins = "I2C_CLK", "I2C_DAT";
function = "func2";
input-enable;
bias-pull-up;
};
};
};
gic: interrupt-controller@1bdc0000 {
compatible = "mti,gic";
reg = <0x1bdc0000 0x20000>;
interrupt-controller;
#interrupt-cells = <3>;
mti,reserved-ipi-vectors = <0 8>;
timer {
compatible = "mti,gic-timer";
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
clocks = <&clk CLK_MUXDIV_CPU>;
};
};
};
};

View File

@ -0,0 +1,140 @@
/dts-v1/;
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include "sf19a2890.dtsi"
/ {
model = "Siflower SF19A2890 Evaluation Board";
compatible = "siflower,sf19a2890-evb", "siflower,sf19a2890";
aliases {
led-boot = &led_wlan;
led-failsafe = &led_wlan;
led-running = &led_wlan;
led-upgrade = &led_wlan;
};
chosen {
stdout-path = "serial0:115200n8";
};
memory@0 {
device_type = "memory";
reg = <0x0 0x8000000>;
};
leds {
compatible = "gpio-leds";
led_wlan: wlan {
function = LED_FUNCTION_WLAN;
color = <LED_COLOR_ID_RED>;
gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
};
};
keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
rtl8367rb {
compatible = "realtek,rtl8367b";
realtek,extif = <6 0 0 1 1 1 1 1 1 2>;
mii-bus = <&mdio>;
phy-id = <0>;
};
};
&gmac {
status = "okay";
phy-mode = "rgmii-id";
snps,ps-speed = <1000>;
nvmem-cells = <&macaddr_factory_0>, <&rgmii_delay_factory_b2>;
nvmem-cell-names = "mac-address", "rgmii-delay";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
&wlan_rf {
status = "okay";
};
&uart0 {
status = "okay";
};
&usb {
status = "okay";
};
&usb_phy {
status = "okay";
};
&spi {
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
#address-cells = <1>;
#size-cells = <1>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "spl-loader";
reg = <0x0 0x20000>; /* 128k */
read-only;
};
partition@20000 {
label = "u-boot";
reg = <0x20000 0x60000>; /* 384k */
};
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x10000>; /* 64k */
};
factory: partition@90000 {
label = "factory";
reg = <0x90000 0x10000>; /* 64k */
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_factory_0: macaddr@0 {
reg = <0x0 0x6>;
};
rgmii_delay_factory_b2: rgmii-delay@b2 {
reg = <0xb2 0x4>;
};
};
};
partition@a0000 {
compatible = "denx,uimage";
label = "firmware";
reg = <0xa0000 0x0>; /* 640k- */
};
};
};
};

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_MACH_SIFLOWER_KMALLOC_H
#define __ASM_MACH_SIFLOWER_KMALLOC_H
#ifdef CONFIG_DMA_NONCOHERENT
#define ARCH_DMA_MINALIGN 32
#endif
#endif /* __ASM_MACH_SIFLOWER_KMALLOC_H */

View File

@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
menuconfig CLK_SIFLOWER
bool "Siflower SoC driver support"
depends on MIPS || COMPILE_TEST
help
SoC drivers for Siflower Linux-capable SoCs.
if CLK_SIFLOWER
config CLK_SF19A2890
bool "Clock driver for Siflower CLK_SF19A2890"
depends on MIPS || COMPILE_TEST
help
Supports the Top Clock Module found in SF19A2890. If this
kernel is meant to run on a Siflower SF19A2890 SoC,
enable this driver.
config CLK_SF19A2890_PERIPH
bool "Clock driver for Siflower SF19A2890 peripheral clock gates"
depends on MIPS || COMPILE_TEST
help
Supports the clock gates for various peripherals in SF19A2890.
If this kernel is meant to run on a Siflower SF19A2890 SoC,
enable this driver.
endif

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_CLK_SF19A2890) += clk-sf19a2890.o
obj-$(CONFIG_CLK_SF19A2890_PERIPH) += clk-sf19a2890-periph.o

View File

@ -0,0 +1,170 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/of_clk.h>
#include <linux/of.h>
#include <linux/spinlock.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#define REG_GATE 0x0
/*
* A shared 'Bus Output Enable' signal for all APB peripherals. The peripheral
* only responds to bus requests if its dedicated clock is enabled and this
* shared BOE is set.
*/
#define REG_BOE 0x8
#define BOE_EN GENMASK(1, 0)
struct sf19a2890_periphclk {
void __iomem *base;
struct clk_hw hw;
u32 idx;
};
struct sf19a2890_periphclk_priv {
struct sf19a2890_periphclk *gates;
struct clk_hw_onecell_data clk_data;
};
static inline struct sf19a2890_periphclk *hw_to_periphclk(struct clk_hw *hw)
{
return container_of(hw, struct sf19a2890_periphclk, hw);
}
static int sf19a2890_periphclk_enable(struct clk_hw *hw)
{
struct sf19a2890_periphclk *priv = hw_to_periphclk(hw);
u32 reg = readl(priv->base + REG_GATE);
writel(reg | BIT(priv->idx), priv->base + REG_GATE);
writel(BOE_EN, priv->base + REG_BOE);
return 0;
}
static void sf19a2890_periphclk_disable(struct clk_hw *hw)
{
struct sf19a2890_periphclk *priv = hw_to_periphclk(hw);
u32 reg = readl(priv->base + REG_GATE);
reg &= ~BIT(priv->idx);
writel(reg, priv->base + REG_GATE);
if (reg == 0)
writel(0, priv->base + REG_BOE);
}
static int sf19a2890_periphclk_is_enabled(struct clk_hw *hw)
{
struct sf19a2890_periphclk *priv = hw_to_periphclk(hw);
return !!(readl(priv->base + REG_GATE) & BIT(priv->idx));
}
static const struct clk_ops sf19a28_periphclk_ops = {
.enable = sf19a2890_periphclk_enable,
.disable = sf19a2890_periphclk_disable,
.is_enabled = sf19a2890_periphclk_is_enabled,
};
static void __init sf19a2890_periphclk_init(struct device_node *node)
{
struct clk_init_data init = {};
struct sf19a2890_periphclk_priv *priv;
u32 reg, valid_gates, critical_gates;
int num_clks, i, ret, idx;
const char *name, *parent;
void __iomem *base;
num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells");
if (num_clks < 1 || num_clks > 32)
return;
ret = of_property_read_u32(node, "siflower,valid-gates", &valid_gates);
if (ret < 0)
valid_gates = BIT(num_clks) - 1;
ret = of_property_read_u32(node, "siflower,critical-gates", &critical_gates);
if (ret < 0)
critical_gates = 0;
priv = kzalloc(struct_size(priv, clk_data.hws, num_clks), GFP_KERNEL);
if (!priv)
return;
priv->clk_data.num = num_clks;
priv->gates = kcalloc(num_clks, sizeof(struct sf19a2890_periphclk),
GFP_KERNEL);
if (!priv->gates)
goto err1;
base = of_iomap(node, 0);
if (!base) {
pr_err("failed to map resources.\n");
goto err2;
}
/* clear unused higher bits for BOE check in disable call. */
reg = readl(base + REG_GATE);
reg &= valid_gates;
writel(reg, base + REG_GATE);
for (i = 0, idx = 0; i < num_clks && idx < 32; i++, idx++) {
ret = of_property_read_string_index(node, "clock-output-names",
i, &name);
if (ret != 0) {
pr_err("failed to read output name for the %dth gate.\n",
i);
goto err3;
}
parent = of_clk_get_parent_name(node, i);
if (!parent) {
pr_err("failed to get parent clock for the %dth gate.\n",
i);
goto err3;
}
while (!(valid_gates & BIT(idx))) {
idx++;
if (idx >= 32) {
pr_err("too few valid gates.");
goto err3;
}
}
priv->gates[i].base = base;
priv->gates[i].idx = idx;
init.name = name;
init.ops = &sf19a28_periphclk_ops;
init.parent_names = &parent;
init.num_parents = 1;
init.flags = (critical_gates & BIT(idx)) ? CLK_IS_CRITICAL : 0;
priv->gates[i].hw.init = &init;
ret = clk_hw_register(NULL, &priv->gates[i].hw);
if (ret) {
pr_err("failed to register the %dth gate: %d.\n", i,
ret);
goto err3;
}
priv->clk_data.hws[i] = &priv->gates[i].hw;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
&priv->clk_data);
if (ret) {
pr_err("failed to add hw provider.\n");
goto err3;
}
return;
err3:
for (i--; i >= 0; i--)
clk_hw_unregister_gate(priv->clk_data.hws[i]);
err2:
kfree(priv->gates);
err1:
kfree(priv);
}
CLK_OF_DECLARE(sf19a2890_periphclk, "siflower,sf19a2890-periph-clk",
sf19a2890_periphclk_init);

View File

@ -0,0 +1,414 @@
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/compiler.h>
#include <linux/clk-provider.h>
#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/bug.h>
#include <dt-bindings/clock/siflower,sf19a2890-clk.h>
#define REG_PLL_BASE 0x0
#define REG_PLL_PD 0x0
#define PLL_PD BIT(0)
#define PLL_PD_VCO BIT(1)
#define PLL_PD_POSTDIV BIT(2)
#define PLL_PD_4PHASE BIT(3)
#define PLL_PD_DAC BIT(4)
#define PLL_PD_DSM BIT(5)
/*
* PLL_PARAM is a 48-bit value put into 6 registers, 8-bit per register:
* REFDIV = PLL_PARAM[47:42]
* POSTDIV2 = PLL_PARAM[41:39]
* POSTDIV1 = PLL_PARAM[38:36]
* FRAC = PLL_PARAM[35:12]
* FBDIV = PLL_PARAM[11:0]
*/
#define REG_PLL_PARAM(_x) (0x4 + (_x) * 4)
#define PLL_REFDIV_HI 47
#define PLL_REFDIV_LO 42
#define PLL_POSTDIV2_HI 41
#define PLL_POSTDIV2_LO 39
#define PLL_POSTDIV1_HI 38
#define PLL_POSTDIV1_LO 36
#define PLL_FRAC_HI 35
#define PLL_FRAC_LO 12
#define PLL_FRAC_BITS (PLL_FRAC_HI - PLL_FRAC_LO + 1)
#define PLL_FBDIV_HI 11
#define PLL_FBDIV_LO 0
#define REG_PLL_CFG 0x1c
#define PLL_CFG_BYPASS BIT(0)
#define PLL_CFG_SRC GENMASK(2, 1)
#define PLL_CFG_OCLK_SEL BIT(3)
#define PLL_CFG_OCLK_GATE BIT(4)
#define PLL_CFG_LOAD_DIVS BIT(5)
#define REG_PLL_LOCK 0x20
/*
* Read-only register indicating the value of the hardware clock source
* override pin. When the first bit of this register is set, PLL clock
* source is forced to the 40M oscillator regardless of PLL_CFG_SRC
* value.
*/
#define REG_PLL_SRC_OVERRIDE 0x24
struct sf_clk_common {
void __iomem *base;
spinlock_t *lock;
struct clk_hw hw;
};
struct sf19a2890_clk {
struct sf_clk_common common;
ulong offset;
};
#define SF_CLK_COMMON(_name, _parents, _op, _flags) \
{ \
.hw.init = CLK_HW_INIT_PARENTS(_name, _parents, _op, _flags), \
}
static inline struct sf_clk_common *hw_to_sf_clk_common(struct clk_hw *hw)
{
return container_of(hw, struct sf_clk_common, hw);
}
static inline struct sf19a2890_clk *cmn_to_clk(struct sf_clk_common *cmn_priv)
{
return container_of(cmn_priv, struct sf19a2890_clk, common);
}
static inline u32 sf_readl(struct sf_clk_common *priv, u32 reg)
{
return readl(priv->base + reg);
}
static inline void sf_writel(struct sf_clk_common *priv, u32 reg, u32 val)
{
return writel(val, priv->base + reg);
}
static inline void sf_rmw(struct sf_clk_common *priv, u32 reg, u32 clr, u32 set)
{
u32 val = sf_readl(priv, reg);
val &= ~clr;
val |= set;
sf_writel(priv, reg, val);
}
static u32 sf_pll_param_get(struct sf19a2890_clk *priv, u32 hi, u32 lo)
{
struct sf_clk_common *cmn = &priv->common;
u32 ret = 0;
int reg_hi = hi / 8;
int reg_lo = lo / 8;
u32 reg_hi_pos = hi % 8;
u32 reg_lo_pos = lo % 8;
int i;
if (reg_hi == reg_lo) {
u32 mask = (BIT(reg_hi_pos - reg_lo_pos + 1)) - 1;
u32 reg_val =
sf_readl(cmn, priv->offset + REG_PLL_PARAM(reg_hi));
return (reg_val >> reg_lo_pos) & mask;
}
ret = sf_readl(cmn, priv->offset + REG_PLL_PARAM(reg_hi)) &
(BIT(reg_hi_pos + 1) - 1);
for (i = reg_hi - 1; i > reg_lo; i--)
ret = (ret << 8) |
sf_readl(cmn, priv->offset + REG_PLL_PARAM(i));
ret = (ret << (8 - reg_lo_pos)) |
(sf_readl(cmn, priv->offset + REG_PLL_PARAM(reg_lo)) >>
reg_lo_pos);
return ret;
}
static unsigned long sf19a28_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
u32 refdiv = sf_pll_param_get(priv, PLL_REFDIV_HI, PLL_REFDIV_LO);
u32 fbdiv = sf_pll_param_get(priv, PLL_FBDIV_HI, PLL_FBDIV_LO);
u32 postdiv1 = sf_pll_param_get(priv, PLL_POSTDIV1_HI, PLL_POSTDIV1_LO);
u32 postdiv2 = sf_pll_param_get(priv, PLL_POSTDIV2_HI, PLL_POSTDIV2_LO);
u32 pll_pd = sf_readl(cmn_priv, PLL_PD);
u32 ref = parent_rate / refdiv;
u32 rate = ref * fbdiv;
u32 frac;
u64 frac_rate;
if (!(pll_pd & PLL_PD_DSM)) {
frac = sf_pll_param_get(priv, PLL_FRAC_HI, PLL_FRAC_LO);
frac_rate = ((u64)rate * frac) >> PLL_FRAC_BITS;
rate += frac_rate;
}
rate = rate / postdiv1 / postdiv2;
return rate;
}
static u8 sf19a28_pll_get_parent(struct clk_hw *hw)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
u32 cfg;
if (sf_readl(cmn_priv, priv->offset + REG_PLL_SRC_OVERRIDE))
return 1;
cfg = sf_readl(cmn_priv, priv->offset + REG_PLL_CFG);
return (FIELD_GET(PLL_CFG_SRC, cfg) == 1);
}
static const struct clk_ops sf19a28_pll_ops = {
.recalc_rate = sf19a28_pll_recalc_rate,
.get_parent = sf19a28_pll_get_parent,
};
static const char * const clk_pll_parents[] = { "osc12m", "osc40m" };
#define SF19A28_PLL(_name, _offset, _flags) \
struct sf19a2890_clk _name = { \
.common = SF_CLK_COMMON(#_name, clk_pll_parents, \
&sf19a28_pll_ops, _flags), \
.offset = REG_PLL_BASE + _offset, \
}
static SF19A28_PLL(pll_cpu, 0x0, 0);
static SF19A28_PLL(pll_ddr, 0x40, 0);
static SF19A28_PLL(pll_cmn, 0x80, 0);
#define REG_MUXDIV_BASE 0x400
#define REG_MUXDIV_CFG 0x0
#define MUXDIV_USE_NCO BIT(3)
#define MUXDIV_SRC_SEL GENMASK(2, 0)
#define REG_MUXDIV_RATIO 0x4
#define MUXDIV_RATIO_MAX 0xff
#define REG_MUXDIV_NCO_V 0x8
#define REG_MUXDIV_EN 0xc
#define REG_MUXDIV_XN_DIV_RATIO 0x10
#define MUXDIV_XN_DIV_MAX 3
static unsigned long sf19a28_muxdiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
u32 div;
div = sf_readl(cmn_priv, priv->offset + REG_MUXDIV_RATIO) + 1;
return parent_rate / div;
}
int sf19a28_muxdiv_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
unsigned int div;
div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
if (!div)
div = 1;
else if (div > MUXDIV_RATIO_MAX + 1)
div = MUXDIV_RATIO_MAX + 1;
req->rate = req->best_parent_rate / div;
return 0;
}
static int sf19a28_muxdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
unsigned int div;
div = DIV_ROUND_CLOSEST(parent_rate, rate);
if (div < 1)
div = 1;
else if (div > MUXDIV_RATIO_MAX + 1)
div = MUXDIV_RATIO_MAX + 1;
div -= 1;
sf_writel(cmn_priv, priv->offset + REG_MUXDIV_RATIO, div);
return 0;
}
static int sf19a28_muxdiv_enable(struct clk_hw *hw)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
sf_writel(cmn_priv, priv->offset + REG_MUXDIV_EN, 1);
return 0;
}
static void sf19a28_muxdiv_disable(struct clk_hw *hw)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
sf_writel(cmn_priv, priv->offset + REG_MUXDIV_EN, 0);
}
static int sf19a28_muxdiv_is_enabled(struct clk_hw *hw)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
return !!sf_readl(cmn_priv, priv->offset + REG_MUXDIV_EN);
}
static u8 sf19a28_muxdiv_get_parent(struct clk_hw *hw)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
u32 cfg = sf_readl(cmn_priv, priv->offset + REG_MUXDIV_CFG);
u32 src = FIELD_GET(MUXDIV_SRC_SEL, cfg);
if (src <= 2)
return src;
if (src == 4)
return 3;
return 4;
}
static int sf19a28_muxdiv_set_parent(struct clk_hw *hw, u8 index)
{
struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
struct sf19a2890_clk *priv = cmn_to_clk(cmn_priv);
u32 src;
if (index <= 2)
src = index;
else if (index == 3)
src = 4;
else
src = 6;
sf_writel(cmn_priv, priv->offset + REG_MUXDIV_CFG, src);
return 0;
}
static const char * const clk_muxdiv_parents[] = { "pll_cpu", "pll_ddr", "pll_cmn",
"osc12m", "osc40m" };
static const struct clk_ops sf19a28_muxdiv_ops = {
.recalc_rate = sf19a28_muxdiv_recalc_rate,
.determine_rate = sf19a28_muxdiv_determine_rate,
.set_rate = sf19a28_muxdiv_set_rate,
.enable = sf19a28_muxdiv_enable,
.disable = sf19a28_muxdiv_disable,
.is_enabled = sf19a28_muxdiv_is_enabled,
.get_parent = sf19a28_muxdiv_get_parent,
.set_parent = sf19a28_muxdiv_set_parent,
};
#define SF19A28_MUXDIV(_name, _offset, _flags) \
struct sf19a2890_clk _name = { \
.common = SF_CLK_COMMON(#_name, clk_muxdiv_parents, \
&sf19a28_muxdiv_ops, _flags), \
.offset = REG_MUXDIV_BASE + _offset, \
}
static SF19A28_MUXDIV(muxdiv_bus1, 0x0, CLK_IS_CRITICAL);
static SF19A28_MUXDIV(muxdiv_bus2, 0x20, CLK_IS_CRITICAL);
static SF19A28_MUXDIV(muxdiv_bus3, 0x40, CLK_IS_CRITICAL);
static SF19A28_MUXDIV(muxdiv_cpu, 0x100, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT);
static SF19A28_MUXDIV(muxdiv_pbus, 0x120, CLK_IS_CRITICAL);
static SF19A28_MUXDIV(muxdiv_mem_phy, 0x140, CLK_IS_CRITICAL);
static SF19A28_MUXDIV(muxdiv_uart, 0x180, 0);
static SF19A28_MUXDIV(muxdiv_eth_ref, 0x200, 0);
static SF19A28_MUXDIV(muxdiv_eth_byp_ref, 0x220, 0);
static SF19A28_MUXDIV(muxdiv_eth_tsu, 0x240, 0);
static SF19A28_MUXDIV(muxdiv_gmac_byp_ref, 0x260, 0);
static SF19A28_MUXDIV(muxdiv_m6250_0, 0x280, 0);
static SF19A28_MUXDIV(muxdiv_m6250_1, 0x2a0, 0);
static SF19A28_MUXDIV(muxdiv_wlan24_plf, 0x2c0, 0);
static SF19A28_MUXDIV(muxdiv_wlan5_plf, 0x2e0, 0);
static SF19A28_MUXDIV(muxdiv_usbphy_ref, 0x300, 0);
static SF19A28_MUXDIV(muxdiv_tclk, 0x320, 0);
static SF19A28_MUXDIV(muxdiv_npu_pe, 0x340, 0);
static struct clk_hw_onecell_data sf19a2890_hw_clks = {
.num = CLK_SF19A2890_MAX,
.hws = {
[CLK_PLL_CPU] = &pll_cpu.common.hw,
[CLK_PLL_DDR] = &pll_ddr.common.hw,
[CLK_PLL_CMN] = &pll_cmn.common.hw,
[CLK_MUXDIV_BUS1] = &muxdiv_bus1.common.hw,
[CLK_MUXDIV_BUS2] = &muxdiv_bus2.common.hw,
[CLK_MUXDIV_BUS3] = &muxdiv_bus3.common.hw,
[CLK_MUXDIV_CPU] = &muxdiv_cpu.common.hw,
[CLK_MUXDIV_PBUS] = &muxdiv_pbus.common.hw,
[CLK_MUXDIV_MEM_PHY] = &muxdiv_mem_phy.common.hw,
[CLK_MUXDIV_UART] = &muxdiv_uart.common.hw,
[CLK_MUXDIV_ETH_REF] = &muxdiv_eth_ref.common.hw,
[CLK_MUXDIV_ETH_BYP_REF] = &muxdiv_eth_byp_ref.common.hw,
[CLK_MUXDIV_ETH_TSU] = &muxdiv_eth_tsu.common.hw,
[CLK_MUXDIV_GMAC_BYP_REF] = &muxdiv_gmac_byp_ref.common.hw,
[CLK_MUXDIV_M6250_0] = &muxdiv_m6250_0.common.hw,
[CLK_MUXDIV_M6250_1] = &muxdiv_m6250_1.common.hw,
[CLK_MUXDIV_WLAN24_PLF] = &muxdiv_wlan24_plf.common.hw,
[CLK_MUXDIV_WLAN5_PLF] = &muxdiv_wlan5_plf.common.hw,
[CLK_MUXDIV_USBPHY_REF] = &muxdiv_usbphy_ref.common.hw,
[CLK_MUXDIV_TCLK] = &muxdiv_tclk.common.hw,
[CLK_MUXDIV_NPU_PE_CLK] = &muxdiv_npu_pe.common.hw,
},
};
struct sf19a2890_clk_ctrl {
void __iomem *base;
spinlock_t lock;
};
static void __init sf19a2890_clk_init(struct device_node *node)
{
struct sf19a2890_clk_ctrl *ctrl;
int i, ret;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return;
ctrl->base = of_iomap(node, 0);
if (!ctrl->base) {
pr_err("failed to map resources.\n");
return;
}
spin_lock_init(&ctrl->lock);
for (i = 0; i < sf19a2890_hw_clks.num; i++) {
struct clk_hw *hw = sf19a2890_hw_clks.hws[i];
struct sf_clk_common *common;
if (!hw)
continue;
common = hw_to_sf_clk_common(hw);
common->base = ctrl->base;
common->lock = &ctrl->lock;
ret = clk_hw_register(NULL, hw);
if (ret) {
pr_err("Couldn't register clock %d: %d\n", i, ret);
goto err;
}
}
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &sf19a2890_hw_clks);
if (ret) {
pr_err("failed to add hw provider.\n");
goto err;
}
return;
err:
iounmap(ctrl->base);
}
CLK_OF_DECLARE(sf19a2890_clk, "siflower,sf19a2890-clk", sf19a2890_clk_init);

View File

@ -0,0 +1,346 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/pinctrl/consumer.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <asm/div64.h>
#define GPIO_IR(n) (0x40 * (n) + 0x00)
#define GPIO_OR(n) (0x40 * (n) + 0x04)
#define GPIO_OEN(n) (0x40 * (n) + 0x08)
#define GPIO_IMR(n) (0x40 * (n) + 0x0c)
#define GPIO_GPIMR(n) (0x40 * (n) + 0x10)
#define GPIO_PIR(n) (0x40 * (n) + 0x14)
#define GPIO_ITR(n) (0x40 * (n) + 0x18)
#define GPIO_IFR(n) (0x40 * (n) + 0x1c)
#define GPIO_ICR(n) (0x40 * (n) + 0x20)
#define GPIO_GPxIR(n) (0x4 * (n) + 0x4000)
#define GPIOS_PER_GROUP 16
struct sf_gpio_priv {
struct gpio_chip gc;
void __iomem *base;
struct clk *clk;
struct reset_control *rstc;
unsigned int irq[];
};
#define to_sf_gpio(x) container_of(x, struct sf_gpio_priv, gc)
static u32 sf_gpio_rd(struct sf_gpio_priv *priv, unsigned long reg)
{
return readl_relaxed(priv->base + reg);
}
static void sf_gpio_wr(struct sf_gpio_priv *priv, unsigned long reg,
u32 val)
{
writel_relaxed(val, priv->base + reg);
}
static int sf_gpio_get_value(struct gpio_chip *gc, unsigned int offset)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
return sf_gpio_rd(priv, GPIO_IR(offset));
}
static void sf_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
sf_gpio_wr(priv, GPIO_OR(offset), value);
}
static int sf_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
if (sf_gpio_rd(priv, GPIO_OEN(offset)))
return GPIO_LINE_DIRECTION_IN;
else
return GPIO_LINE_DIRECTION_OUT;
}
static int sf_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
sf_gpio_wr(priv, GPIO_OEN(offset), 1);
return 0;
}
static int sf_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
sf_gpio_wr(priv, GPIO_OR(offset), value);
sf_gpio_wr(priv, GPIO_OEN(offset), 0);
return 0;
}
static int sf_gpio_set_debounce(struct gpio_chip *gc, unsigned int offset,
u32 debounce)
{
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned long freq = clk_get_rate(priv->clk);
u64 mul;
/* (ICR + 1) * IFR = debounce_us * clkfreq_mhz / 4 */
mul = (u64)debounce * freq;
do_div(mul, 1000000 * 4);
if (mul > 0xff00)
return -EINVAL;
sf_gpio_wr(priv, GPIO_ICR(offset), 0xff);
sf_gpio_wr(priv, GPIO_IFR(offset), DIV_ROUND_UP(mul, 0x100));
return 0;
}
static int sf_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
unsigned long config)
{
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_INPUT_DEBOUNCE:
return sf_gpio_set_debounce(gc, offset,
pinconf_to_config_argument(config));
default:
return gpiochip_generic_config(gc, offset, config);
}
}
static void sf_gpio_irq_ack(struct irq_data *data)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned long offset = irqd_to_hwirq(data);
sf_gpio_wr(priv, GPIO_PIR(offset), 0);
}
static void sf_gpio_irq_mask(struct irq_data *data)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned long offset = irqd_to_hwirq(data);
sf_gpio_wr(priv, GPIO_IMR(offset), 1);
sf_gpio_wr(priv, GPIO_GPIMR(offset), 1);
}
static void sf_gpio_irq_unmask(struct irq_data *data)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned long offset = irqd_to_hwirq(data);
sf_gpio_wr(priv, GPIO_IMR(offset), 0);
sf_gpio_wr(priv, GPIO_GPIMR(offset), 0);
}
/* We are actually setting the parents' affinity. */
static int sf_gpio_irq_set_affinity(struct irq_data *data,
const struct cpumask *dest, bool force)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
unsigned long offset = irqd_to_hwirq(data);
const struct cpumask *pdest;
struct irq_desc *pdesc;
struct irq_data *pdata;
unsigned int group;
int ret;
/* Find the parent IRQ and call its irq_set_affinity */
group = offset / GPIOS_PER_GROUP;
if (group >= gc->irq.num_parents)
return -EINVAL;
pdesc = irq_to_desc(gc->irq.parents[group]);
if (!pdesc)
return -EINVAL;
pdata = irq_desc_get_irq_data(pdesc);
if (!pdata->chip->irq_set_affinity)
return -EINVAL;
ret = pdata->chip->irq_set_affinity(pdata, dest, force);
if (ret < 0)
return ret;
/* Copy its effective_affinity back */
pdest = irq_data_get_effective_affinity_mask(pdata);
irq_data_update_effective_affinity(data, pdest);
return ret;
}
static int sf_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned long offset = irqd_to_hwirq(data);
u32 val;
switch (flow_type) {
case IRQ_TYPE_EDGE_RISING:
val = 4;
break;
case IRQ_TYPE_EDGE_FALLING:
val = 2;
break;
case IRQ_TYPE_EDGE_BOTH:
val = 6;
break;
case IRQ_TYPE_LEVEL_HIGH:
val = 1;
break;
case IRQ_TYPE_LEVEL_LOW:
val = 0;
break;
default:
return -EINVAL;
}
sf_gpio_wr(priv, GPIO_ITR(offset), val);
if (flow_type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(data, handle_level_irq);
else
irq_set_handler_locked(data, handle_edge_irq);
return 0;
}
static const struct irq_chip sf_gpio_irqchip = {
.name = KBUILD_MODNAME,
.irq_ack = sf_gpio_irq_ack,
.irq_mask = sf_gpio_irq_mask,
.irq_unmask = sf_gpio_irq_unmask,
.irq_set_affinity = sf_gpio_irq_set_affinity,
.irq_set_type = sf_gpio_irq_set_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void sf_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct irq_chip *ic = irq_desc_get_chip(desc);
struct sf_gpio_priv *priv = to_sf_gpio(gc);
unsigned int irq = irq_desc_get_irq(desc);
unsigned int group = irq - priv->irq[0];
unsigned long pending;
unsigned int n;
chained_irq_enter(ic, desc);
pending = sf_gpio_rd(priv, GPIO_GPxIR(group));
for_each_set_bit(n, &pending, GPIOS_PER_GROUP) {
generic_handle_domain_irq(gc->irq.domain,
n + group * GPIOS_PER_GROUP);
}
chained_irq_exit(ic, desc);
}
static int sf_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sf_gpio_priv *priv;
struct gpio_irq_chip *girq;
struct gpio_chip *gc;
u32 ngpios, ngroups;
int ret, i;
ngpios = (unsigned int) device_get_match_data(dev);
ngroups = DIV_ROUND_UP(ngpios, GPIOS_PER_GROUP);
priv = devm_kzalloc(dev, struct_size(priv, irq, ngroups), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
priv->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
priv->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
ret = reset_control_deassert(priv->rstc);
if (ret)
return ret;
for (i = 0; i < ngroups; i++) {
ret = platform_get_irq(pdev, i);
if (ret < 0)
return ret;
priv->irq[i] = ret;
}
gc = &priv->gc;
gc->label = KBUILD_MODNAME;
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
gc->get_direction = sf_gpio_get_direction;
gc->direction_input = sf_gpio_direction_input;
gc->direction_output = sf_gpio_direction_output;
gc->get = sf_gpio_get_value;
gc->set = sf_gpio_set_value;
gc->set_config = sf_gpio_set_config;
gc->base = -1;
gc->ngpio = ngpios;
girq = &gc->irq;
gpio_irq_chip_set_chip(girq, &sf_gpio_irqchip);
girq->num_parents = ngroups;
girq->parents = priv->irq;
girq->parent_handler = sf_gpio_irq_handler;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
platform_set_drvdata(pdev, priv);
return devm_gpiochip_add_data(dev, gc, priv);
}
static int sf_gpio_remove(struct platform_device *pdev)
{
struct sf_gpio_priv *priv = platform_get_drvdata(pdev);
reset_control_assert(priv->rstc);
return 0;
}
static const struct of_device_id sf_gpio_ids[] = {
{ .compatible = "siflower,sf19a2890-gpio", .data = (void *)49 },
{},
};
MODULE_DEVICE_TABLE(of, sf_gpio_ids);
static struct platform_driver sf_gpio_driver = {
.probe = sf_gpio_probe,
.remove = sf_gpio_remove,
.driver = {
.name = "siflower_gpio",
.owner = THIS_MODULE,
.of_match_table = sf_gpio_ids,
},
};
module_platform_driver(sf_gpio_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qingfang Deng <qingfang.deng@siflower.com.cn>");
MODULE_DESCRIPTION("GPIO driver for SiFlower SoCs");

View File

@ -0,0 +1,193 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Siflower SF19A2890 GMAC glue layer
* SF19A2890 GMAC is a DWMAC 3.73a with a custom HNAT engine
* between its MAC and DMA engine.
*
* Copyright (C) 2024 Chuanhong Guo <gch981213@gmail.com>
*/
#include <linux/of_net.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/nvmem-consumer.h>
#include "stmmac.h"
#include "stmmac_platform.h"
struct sf19a2890_gmac_priv {
struct device *dev;
void __iomem *gmac_cfg;
struct clk *gmac_byp_ref_clk;
};
#define REG_MISC 0x0
#define MISC_PHY_INTF_SEL GENMASK(2, 0)
#define PHY_IF_GMII_MII 0
#define PHY_IF_RGMII 1
#define PHY_IF_RMII 4
#define MISC_PTP_AUX_TS_TRIG BIT(3)
#define MISC_SBD_FLOWCTRL BIT(4)
#define CLK_RMII_OEN BIT(5)
#define REG_CLK_TX_DELAY 0x4
#define REG_CLK_RX_PHY_DELAY 0x8
#define REG_CLK_RX_PHY_DELAY_EN 0xc
/* Siflower stores RGMII delay as a 4-byte hex string in MTD. */
#define SFGMAC_DELAY_STR_LEN 4
static int sfgmac_set_delay_from_nvmem(struct sf19a2890_gmac_priv *priv)
{
struct device_node *np = priv->dev->of_node;
int ret = 0;
struct nvmem_cell *cell;
const void *data;
size_t retlen;
u16 gmac_delay;
u8 delay_tx, delay_rx;
cell = of_nvmem_cell_get(np, "rgmii-delay");
if (IS_ERR(cell))
return PTR_ERR(cell);
data = nvmem_cell_read(cell, &retlen);
nvmem_cell_put(cell);
if (IS_ERR(data))
return PTR_ERR(data);
if (retlen < SFGMAC_DELAY_STR_LEN) {
ret = -EINVAL;
goto exit;
}
ret = kstrtou16(data, 16, &gmac_delay);
if (ret == 0) {
delay_tx = (gmac_delay >> 8) & 0xff;
delay_rx = gmac_delay & 0xff;
writel(delay_tx, priv->gmac_cfg + REG_CLK_TX_DELAY);
writel(delay_rx, priv->gmac_cfg + REG_CLK_RX_PHY_DELAY);
if (delay_rx)
writel(1, priv->gmac_cfg + REG_CLK_RX_PHY_DELAY_EN);
}
exit:
kfree(data);
return ret;
}
static int sfgmac_setup_phy_interface(struct sf19a2890_gmac_priv *priv)
{
phy_interface_t phy_iface;
int mode;
u32 reg;
of_get_phy_mode(priv->dev->of_node, &phy_iface);
switch (phy_iface) {
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
mode = PHY_IF_GMII_MII;
break;
case PHY_INTERFACE_MODE_RMII:
mode = PHY_IF_RMII;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
mode = PHY_IF_RGMII;
break;
default:
return -EOPNOTSUPP;
}
reg = readl(priv->gmac_cfg + REG_MISC);
reg &= ~MISC_PHY_INTF_SEL;
reg |= FIELD_PREP(MISC_PHY_INTF_SEL, mode);
writel(reg, priv->gmac_cfg + REG_MISC);
return 0;
}
static int sf19a2890_gmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
struct sf19a2890_gmac_priv *priv;
struct stmmac_resources stmmac_res;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
priv->gmac_byp_ref_clk = devm_clk_get_enabled(&pdev->dev, "gmac_byp_ref");
if (IS_ERR(priv->gmac_byp_ref_clk))
return PTR_ERR(priv->gmac_byp_ref_clk);
priv->gmac_cfg = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(priv->gmac_cfg)) {
dev_err(&pdev->dev, "failed to map regs for gmac config.\n");
return PTR_ERR(priv->gmac_cfg);
}
ret = sfgmac_set_delay_from_nvmem(priv);
if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
ret = sfgmac_setup_phy_interface(priv);
if (ret)
return ret;
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret)
return ret;
plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
if (IS_ERR(plat_dat)) {
dev_err(&pdev->dev, "dt configuration failed\n");
return PTR_ERR(plat_dat);
}
plat_dat->bsp_priv = priv;
/* This DWMAC has PCSSEL set, but it's not SGMII capable, and doesn't
* return anything in PCS registers under RGMII mode.
* Set this flag to bypass reading pcs regs stmmac_ethtool_get_link_ksettings.
* No idea if it's correct or not.
*/
plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS;
ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
if (ret)
goto err_remove_config_dt;
return 0;
err_remove_config_dt:
if (pdev->dev.of_node)
stmmac_remove_config_dt(pdev, plat_dat);
return ret;
}
static const struct of_device_id dwmac_sf19a2890_match[] = {
{ .compatible = "siflower,sf19a2890-gmac"},
{ }
};
MODULE_DEVICE_TABLE(of, dwmac_sf19a2890_match);
static struct platform_driver sf19a2890_gmac_driver = {
.probe = sf19a2890_gmac_probe,
.remove_new = stmmac_pltfr_remove,
.driver = {
.name = "sf19a2890-gmac",
.pm = &stmmac_pltfr_pm_ops,
.of_match_table = dwmac_sf19a2890_match,
},
};
module_platform_driver(sf19a2890_gmac_driver);
MODULE_DESCRIPTION("SF19A2890 GMAC driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,6 @@
config PHY_SF19A2890_USB
tristate "SIFLOWER sf19a2890 USB2.0 PHY driver"
default n
select GENERIC_PHY
help
Enable this to support the USB2.0 PHY on the SIFLOWER SF19A2890.

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_PHY_SF19A2890_USB) += phy-sf19a2890-usb.o

View File

@ -0,0 +1,145 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#define USB_SLEEPM 0x4
struct sf19a2890_usb_phy {
struct device *dev;
struct clk *phy_clk;
struct reset_control *usb_phy_rst;
struct reset_control *power_on_rst;
void __iomem *base;
};
static int sf19a2890_usb_phy_power_on(struct phy *phy)
{
struct sf19a2890_usb_phy *p_phy = phy_get_drvdata(phy);
int ret;
ret = clk_prepare_enable(p_phy->phy_clk);
if (ret < 0) {
dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
return ret;
}
ret = reset_control_deassert(p_phy->usb_phy_rst);
if (ret)
goto err1;
ret = reset_control_deassert(p_phy->power_on_rst);
if (ret)
goto err2;
writel(1, p_phy->base + USB_SLEEPM);
return 0;
err2:
reset_control_assert(p_phy->usb_phy_rst);
err1:
clk_disable_unprepare(p_phy->phy_clk);
return ret;
}
static int sf19a2890_usb_phy_power_off(struct phy *phy)
{
struct sf19a2890_usb_phy *p_phy = phy_get_drvdata(phy);
writel(0, p_phy->base + USB_SLEEPM);
reset_control_assert(p_phy->power_on_rst);
reset_control_assert(p_phy->usb_phy_rst);
clk_disable_unprepare(p_phy->phy_clk);
return 0;
}
static const struct phy_ops sf19a2890_usb_phy_ops = {
.power_on = sf19a2890_usb_phy_power_on,
.power_off = sf19a2890_usb_phy_power_off,
.owner = THIS_MODULE,
};
static int sf19a2890_usb_phy_probe(struct platform_device *pdev)
{
struct sf19a2890_usb_phy *p_phy;
struct phy_provider *provider;
struct phy *phy;
int ret;
p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
if (!p_phy)
return -ENOMEM;
p_phy->dev = &pdev->dev;
p_phy->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(p_phy->base))
return PTR_ERR(p_phy->base);
p_phy->phy_clk = devm_clk_get(p_phy->dev, NULL);
if (IS_ERR(p_phy->phy_clk))
return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->phy_clk),
"failed to get usb phy clock\n");
p_phy->power_on_rst =
devm_reset_control_get_exclusive(&pdev->dev, "power_on_rst");
if (IS_ERR(p_phy->power_on_rst))
return PTR_ERR(p_phy->power_on_rst);
ret = reset_control_assert(p_phy->power_on_rst);
if (ret)
return ret;
p_phy->usb_phy_rst =
devm_reset_control_get_exclusive(&pdev->dev, "usb_phy_rst");
if (IS_ERR(p_phy->usb_phy_rst))
return PTR_ERR(p_phy->usb_phy_rst);
ret = reset_control_assert(p_phy->usb_phy_rst);
if (ret)
return ret;
phy = devm_phy_create(p_phy->dev, NULL, &sf19a2890_usb_phy_ops);
if (IS_ERR(phy))
return dev_err_probe(p_phy->dev, PTR_ERR(phy),
"Failed to create PHY\n");
phy_set_drvdata(phy, p_phy);
provider =
devm_of_phy_provider_register(p_phy->dev, of_phy_simple_xlate);
if (IS_ERR(provider))
return dev_err_probe(p_phy->dev, PTR_ERR(provider),
"Failed to register PHY provider\n");
platform_set_drvdata(pdev, p_phy);
return 0;
}
static const struct of_device_id sf19a2890_usb_phy_of_match[] = {
{
.compatible = "siflower,sf19a2890-usb-phy",
},
{},
};
MODULE_DEVICE_TABLE(of, sf19a2890_usb_phy_of_match);
static struct platform_driver sf19a2890_usb_phy_driver = {
.probe = sf19a2890_usb_phy_probe,
.driver = {
.name = "sf19a2890-usb-phy",
.of_match_table = sf19a2890_usb_phy_of_match,
},
};
module_platform_driver(sf19a2890_usb_phy_driver);
MODULE_AUTHOR("Ziying Wu <ziying.wu@siflower.com.cn>");
MODULE_DESCRIPTION("Siflower SF19A2890 USB2.0 PHY driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,515 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Siflower SF19A2890 pinctrl.
*
* Based on:
* Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO)
*
* Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
*/
#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#define MODULE_NAME "sf19a2890-pinctrl"
struct sf_pinctrl {
struct device *dev;
void __iomem *base;
struct pinctrl_dev *pctl_dev;
struct pinctrl_desc pctl_desc;
struct pinctrl_gpio_range gpio_range;
};
#define SF19A28_NUM_GPIOS 49
#define SF19A28_REG_PC(pin) ((pin) * 0x8)
#define PC_OEN BIT(7)
#define PC_ST BIT(6)
#define PC_IE BIT(5)
#define PC_PD BIT(4)
#define PC_PU BIT(3)
#define PC_DS GENMASK(2, 0)
#define DRIVE_MIN 6
#define DRIVE_STEP 3
#define DRIVE_MAX (7 * DRIVE_STEP)
#define SF19A28_REG_PMX(pin) ((pin) * 0x8 + 0x4)
/*
* FUNC_SW:
* 0: Override pad output enable with PC_OEN
* 1: take OEN from GPIO or alternative function
* FMUX_SEL:
* 0: Alternative function mode
* 1: GPIO mode
*/
#define PMX_FUNC_SW BIT(3)
#define PMX_FMUX_SEL BIT(2)
#define PMX_MODE GENMASK(1, 0)
static struct pinctrl_pin_desc sf19a2890_gpio_pins[] = {
PINCTRL_PIN(0, "JTAG_TDO"),
PINCTRL_PIN(1, "JTAG_TDI"),
PINCTRL_PIN(2, "JTAG_TMS"),
PINCTRL_PIN(3, "JTAG_TCK"),
PINCTRL_PIN(4, "JTAG_RST"),
PINCTRL_PIN(5, "SPI_TXD"),
PINCTRL_PIN(6, "SPI_RXD"),
PINCTRL_PIN(7, "SPI_CLK"),
PINCTRL_PIN(8, "SPI_CSN"),
PINCTRL_PIN(9, "UART_TX"),
PINCTRL_PIN(10, "UART_RX"),
PINCTRL_PIN(11, "I2C_DAT"),
PINCTRL_PIN(12, "I2C_CLK"),
PINCTRL_PIN(13, "RGMII_GTX_CLK"),
PINCTRL_PIN(14, "RGMII_TXCLK"),
PINCTRL_PIN(15, "RGMII_TXD0"),
PINCTRL_PIN(16, "RGMII_TXD1"),
PINCTRL_PIN(17, "RGMII_TXD2"),
PINCTRL_PIN(18, "RGMII_TXD3"),
PINCTRL_PIN(19, "RGMII_TXCTL"),
PINCTRL_PIN(20, "RGMII_RXCLK"),
PINCTRL_PIN(21, "RGMII_RXD0"),
PINCTRL_PIN(22, "RGMII_RXD1"),
PINCTRL_PIN(23, "RGMII_RXD2"),
PINCTRL_PIN(24, "RGMII_RXD3"),
PINCTRL_PIN(25, "RGMII_RXCTL"),
PINCTRL_PIN(26, "RGMII_COL"),
PINCTRL_PIN(27, "RGMII_CRS"),
PINCTRL_PIN(28, "RGMII_MDC"),
PINCTRL_PIN(29, "RGMII_MDIO"),
PINCTRL_PIN(30, "HB0_PA_EN"),
PINCTRL_PIN(31, "HB0_LNA_EN"),
PINCTRL_PIN(32, "HB0_SW_CTRL0"),
PINCTRL_PIN(33, "HB0_SW_CTRL1"),
PINCTRL_PIN(34, "HB1_PA_EN"),
PINCTRL_PIN(35, "HB1_LNA_EN"),
PINCTRL_PIN(36, "HB1_SW_CTRL0"),
PINCTRL_PIN(37, "HB1_SW_CTRL1"),
PINCTRL_PIN(38, "LB0_PA_EN"),
PINCTRL_PIN(39, "LB0_LNA_EN"),
PINCTRL_PIN(40, "LB0_SW_CTRL0"),
PINCTRL_PIN(41, "LB0_SW_CTRL1"),
PINCTRL_PIN(42, "LB1_PA_EN"),
PINCTRL_PIN(43, "LB1_LNA_EN"),
PINCTRL_PIN(44, "LB1_SW_CTRL0"),
PINCTRL_PIN(45, "LB1_SW_CTRL1"),
PINCTRL_PIN(46, "CLK_OUT"),
PINCTRL_PIN(47, "EXT_CLK_IN"),
PINCTRL_PIN(48, "DRVVBUS0"),
};
static const char * const sf19a2890_gpio_groups[] = {
"JTAG_TDO",
"JTAG_TDI",
"JTAG_TMS",
"JTAG_TCK",
"JTAG_RST",
"SPI_TXD",
"SPI_RXD",
"SPI_CLK",
"SPI_CSN",
"UART_TX",
"UART_RX",
"I2C_DAT",
"I2C_CLK",
"RGMII_GTX_CLK",
"RGMII_TXCLK",
"RGMII_TXD0",
"RGMII_TXD1",
"RGMII_TXD2",
"RGMII_TXD3",
"RGMII_TXCTL",
"RGMII_RXCLK",
"RGMII_RXD0",
"RGMII_RXD1",
"RGMII_RXD2",
"RGMII_RXD3",
"RGMII_RXCTL",
"RGMII_COL",
"RGMII_CRS",
"RGMII_MDC",
"RGMII_MDIO",
"HB0_PA_EN",
"HB0_LNA_EN",
"HB0_SW_CTRL0",
"HB0_SW_CTRL1",
"HB1_PA_EN",
"HB1_LNA_EN",
"HB1_SW_CTRL0",
"HB1_SW_CTRL1",
"LB0_PA_EN",
"LB0_LNA_EN",
"LB0_SW_CTRL0",
"LB0_SW_CTRL1",
"LB1_PA_EN",
"LB1_LNA_EN",
"LB1_SW_CTRL0",
"LB1_SW_CTRL1",
"CLK_OUT",
"EXT_CLK_IN",
"DRVVBUS0",
};
#define SF19A28_FUNC0 0
#define SF19A28_FUNC1 1
#define SF19A28_FUNC2 2
#define SF19A28_FUNC3 3
#define SF19A28_NUM_FUNCS 4
static const char * const sf19a2890_functions[] = {
"func0", "func1", "func2", "func3"
};
static inline u32 sf_pinctrl_rd(struct sf_pinctrl *pc, ulong reg)
{
return readl(pc->base + reg);
}
static inline void sf_pinctrl_wr(struct sf_pinctrl *pc, ulong reg, u32 val)
{
writel(val, pc->base + reg);
}
static inline void sf_pinctrl_rmw(struct sf_pinctrl *pc, ulong reg, u32 clr,
u32 set)
{
u32 val;
val = sf_pinctrl_rd(pc, reg);
val &= ~clr;
val |= set;
sf_pinctrl_wr(pc, reg, val);
}
static int sf19a2890_pctl_get_groups_count(struct pinctrl_dev *pctldev)
{
return SF19A28_NUM_GPIOS;
}
static const char *sf19a2890_pctl_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return sf19a2890_gpio_groups[selector];
}
static int sf19a2890_pctl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned selector,
const unsigned **pins,
unsigned *num_pins)
{
*pins = &sf19a2890_gpio_pins[selector].number;
*num_pins = 1;
return 0;
}
static void sf19a2890_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned offset)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
u32 conf = sf_pinctrl_rd(pc, SF19A28_REG_PC(offset));
u32 mux = sf_pinctrl_rd(pc, SF19A28_REG_PMX(offset));
if (!(mux & PMX_FUNC_SW))
seq_puts(s, "Forced OE");
else if (mux & PMX_FMUX_SEL)
seq_puts(s, "GPIO");
else
seq_printf(s, "Func%lu", mux & PMX_MODE);
seq_puts(s, " |");
if (!(conf & PC_OEN) && !(mux & PMX_FUNC_SW))
seq_puts(s, " Output");
if ((conf & PC_ST))
seq_puts(s, " Schmitt_Trigger");
if ((conf & PC_IE))
seq_puts(s, " Input");
if ((conf & PC_PD))
seq_puts(s, " Pull_Down");
if ((conf & PC_PU))
seq_puts(s, " Pull_Up");
seq_printf(s, " Drive: %lu mA",
DRIVE_MIN + (conf & PC_DS) * DRIVE_STEP);
}
static const struct pinctrl_ops sf19a2890_pctl_ops = {
.get_groups_count = sf19a2890_pctl_get_groups_count,
.get_group_name = sf19a2890_pctl_get_group_name,
.get_group_pins = sf19a2890_pctl_get_group_pins,
.pin_dbg_show = sf19a2890_pctl_pin_dbg_show,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinconf_generic_dt_free_map,
};
static int sf19a2890_pmx_free(struct pinctrl_dev *pctldev, unsigned offset)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
sf_pinctrl_rmw(pc, SF19A28_REG_PC(offset), PC_IE, PC_OEN);
sf_pinctrl_rmw(pc, SF19A28_REG_PMX(offset), PMX_FUNC_SW, 0);
return 0;
}
static int sf19a2890_pmx_get_functions_count(struct pinctrl_dev *pctldev)
{
return SF19A28_NUM_FUNCS;
}
static const char *sf19a2890_pmx_get_function_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return sf19a2890_functions[selector];
}
static int sf19a2890_pmx_get_function_groups(struct pinctrl_dev *pctldev,
unsigned selector,
const char *const **groups,
unsigned *const num_groups)
{
/* every pin can do every function */
*groups = sf19a2890_gpio_groups;
*num_groups = SF19A28_NUM_GPIOS;
return 0;
}
static int sf19a2890_pmx_set(struct pinctrl_dev *pctldev,
unsigned func_selector, unsigned group_selector)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
unsigned pin = group_selector;
sf_pinctrl_wr(pc, SF19A28_REG_PMX(pin),
PMX_FUNC_SW | FIELD_PREP(PMX_MODE, func_selector));
return 0;
}
static int sf19a2890_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
/* Set to GPIO mode & Let peripheral control OEN */
sf_pinctrl_wr(pc, SF19A28_REG_PMX(offset), PMX_FUNC_SW | PMX_FMUX_SEL);
/*
* Set PC_IE regardless of whether GPIO is in input mode.
* Otherwise GPIO driver can't read back its status in output mode.
*/
sf_pinctrl_rmw(pc, SF19A28_REG_PC(offset), 0, PC_IE);
return 0;
}
static void sf19a2890_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
sf19a2890_pmx_free(pctldev, offset);
}
static const struct pinmux_ops sf19a2890_pmx_ops = {
.free = sf19a2890_pmx_free,
.get_functions_count = sf19a2890_pmx_get_functions_count,
.get_function_name = sf19a2890_pmx_get_function_name,
.get_function_groups = sf19a2890_pmx_get_function_groups,
.set_mux = sf19a2890_pmx_set,
.gpio_request_enable = sf19a2890_pmx_gpio_request_enable,
.gpio_disable_free = sf19a2890_pmx_gpio_disable_free,
};
static int sf19a2890_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
u32 arg = 0;
u32 val = 0;
if (pin >= SF19A28_NUM_GPIOS)
return -EINVAL;
val = sf_pinctrl_rd(pc, SF19A28_REG_PC(pin));
switch (param) {
case PIN_CONFIG_INPUT_SCHMITT:
val &= PC_ST;
if (val)
arg = 1;
break;
case PIN_CONFIG_INPUT_ENABLE:
val &= PC_IE;
if (val)
arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
val &= PC_PD;
if (val)
arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_UP:
val &= PC_PU;
if (val)
arg = 1;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
arg = DRIVE_MIN + (val & PC_DS) * DRIVE_STEP;
break;
default:
return -ENOTSUPP;
}
*config = pinconf_to_config_packed(param, arg);
return 0;
}
static int sf19a2890_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *configs, unsigned num_configs)
{
struct sf_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u32 arg, val;
int i;
val = sf_pinctrl_rd(pc, SF19A28_REG_PC(pin));
if (pin >= SF19A28_NUM_GPIOS)
return -EINVAL;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (arg)
val |= PC_ST;
else
val &= ~PC_ST;
break;
case PIN_CONFIG_INPUT_ENABLE:
if (arg)
val |= PC_IE;
else
val &= ~PC_IE;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
if (arg) {
val |= PC_PD;
val &= ~PC_PU;
} else {
val &= ~PC_PD;
}
break;
case PIN_CONFIG_BIAS_PULL_UP:
if (arg) {
val |= PC_PU;
val &= ~PC_PD;
} else {
val &= ~PC_PU;
}
break;
case PIN_CONFIG_DRIVE_STRENGTH:
val &= ~PC_DS;
if (arg > DRIVE_MAX)
val |= PC_DS;
else if (arg > DRIVE_MIN)
val |= FIELD_PREP(PC_DS, (arg - DRIVE_MIN) /
DRIVE_STEP);
break;
default:
break;
}
sf_pinctrl_wr(pc, SF19A28_REG_PC(pin), val);
}
return 0;
}
static const struct pinconf_ops sf19a2890_pinconf_ops = {
.is_generic = true,
.pin_config_get = sf19a2890_pinconf_get,
.pin_config_set = sf19a2890_pinconf_set,
};
static const struct pinctrl_desc sf19a2890_pinctrl_desc = {
.name = MODULE_NAME,
.pins = sf19a2890_gpio_pins,
.npins = SF19A28_NUM_GPIOS,
.pctlops = &sf19a2890_pctl_ops,
.pmxops = &sf19a2890_pmx_ops,
.confops = &sf19a2890_pinconf_ops,
.owner = THIS_MODULE,
};
static const struct pinctrl_gpio_range sf_pinctrl_gpio_range = {
.name = MODULE_NAME,
.npins = SF19A28_NUM_GPIOS,
};
static const struct of_device_id sf_pinctrl_match[] = {
{ .compatible = "siflower,sf19a2890-pinctrl" },
{}
};
static int sf_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sf_pinctrl *pc;
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
platform_set_drvdata(pdev, pc);
pc->dev = dev;
pc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pc->base))
return PTR_ERR(pc->base);
pc->pctl_desc = sf19a2890_pinctrl_desc;
pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
if (IS_ERR(pc->pctl_dev))
return PTR_ERR(pc->pctl_dev);
return 0;
}
static struct platform_driver sf_pinctrl_driver = {
.probe = sf_pinctrl_probe,
.driver = {
.name = MODULE_NAME,
.of_match_table = sf_pinctrl_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(sf_pinctrl_driver);
MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
MODULE_DESCRIPTION("Siflower SF19A2890 pinctrl driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,131 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
struct reset_sf19a28_periph_data {
struct reset_controller_dev rcdev;
void __iomem *base;
spinlock_t lock;
u32 reset_masks[];
};
static inline struct reset_sf19a28_periph_data *
to_reset_sf19a28_periph_data(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct reset_sf19a28_periph_data, rcdev);
}
static int reset_sf19a28_periph_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct reset_sf19a28_periph_data *data = to_reset_sf19a28_periph_data(rcdev);
unsigned long flags;
u32 reg;
spin_lock_irqsave(&data->lock, flags);
reg = readl(data->base);
if (assert)
reg |= data->reset_masks[id];
else
reg &= ~data->reset_masks[id];
writel(reg, data->base);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
static int reset_sf19a28_periph_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return reset_sf19a28_periph_update(rcdev, id, true);
}
static int reset_sf19a28_periph_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return reset_sf19a28_periph_update(rcdev, id, false);
}
static int reset_sf19a28_periph_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct reset_sf19a28_periph_data *data = to_reset_sf19a28_periph_data(rcdev);
u32 reg;
reg = readl(data->base);
return !!(reg & data->reset_masks[id]);
}
const struct reset_control_ops reset_sf19a28_periph_ops = {
.assert = reset_sf19a28_periph_assert,
.deassert = reset_sf19a28_periph_deassert,
.status = reset_sf19a28_periph_status,
};
static const struct of_device_id reset_sf19a28_periph_dt_ids[] = {
{ .compatible = "siflower,sf19a2890-periph-reset", },
{ /* sentinel */ },
};
static int reset_sf19a28_periph_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct reset_sf19a28_periph_data *data;
void __iomem *base;
int nr_resets;
int ret, i;
u32 tmp;
nr_resets = of_property_count_u32_elems(node, "siflower,reset-masks");
if (nr_resets < 1) {
ret = of_property_read_u32(node, "siflower,num-resets", &tmp);
if (ret < 0 || tmp < 1)
return -EINVAL;
nr_resets = tmp;
}
if (nr_resets >= 32) {
dev_err(dev, "too many resets.");
return -EINVAL;
}
data = devm_kzalloc(dev, struct_size(data, reset_masks, nr_resets), GFP_KERNEL);
if (!data)
return -ENOMEM;
ret = of_property_read_u32_array(node, "siflower,reset-masks",
data->reset_masks, nr_resets);
if (ret)
for (i = 0; i < nr_resets; i++)
data->reset_masks[i] = BIT(i);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
spin_lock_init(&data->lock);
data->base = base;
data->rcdev.owner = THIS_MODULE;
data->rcdev.nr_resets = nr_resets;
data->rcdev.ops = &reset_sf19a28_periph_ops;
data->rcdev.of_node = dev->of_node;
return devm_reset_controller_register(dev, &data->rcdev);
}
static struct platform_driver reset_sf19a28_periph_driver = {
.probe = reset_sf19a28_periph_probe,
.driver = {
.name = "reset-sf19a2890-periph",
.of_match_table = reset_sf19a28_periph_dt_ids,
},
};
builtin_platform_driver(reset_sf19a28_periph_driver);

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
#ifndef __DT_BINDINGS_CLOCK_SIFLOWER_SF19A2890_CLK_H
#define __DT_BINDINGS_CLOCK_SIFLOWER_SF19A2890_CLK_H
#define CLK_PLL_CPU 0
#define CLK_PLL_DDR 1
#define CLK_PLL_CMN 2
#define CLK_MUXDIV_BUS1 3
#define CLK_MUXDIV_BUS2 4
#define CLK_MUXDIV_BUS3 5
#define CLK_MUXDIV_CPU 6
#define CLK_MUXDIV_PBUS 7
#define CLK_MUXDIV_MEM_PHY 8
#define CLK_MUXDIV_UART 9
#define CLK_MUXDIV_ETH_REF 10
#define CLK_MUXDIV_ETH_BYP_REF 11
#define CLK_MUXDIV_ETH_TSU 12
#define CLK_MUXDIV_GMAC_BYP_REF 13
#define CLK_MUXDIV_M6250_0 14
#define CLK_MUXDIV_M6250_1 15
#define CLK_MUXDIV_WLAN24_PLF 16
#define CLK_MUXDIV_WLAN5_PLF 17
#define CLK_MUXDIV_USBPHY_REF 18
#define CLK_MUXDIV_TCLK 19
#define CLK_MUXDIV_NPU_PE_CLK 20
#define CLK_SF19A2890_MAX 21
#endif /* __DT_BINDINGS_CLOCK_SIFLOWER_SF19A2890_CLK_H */

View File

@ -0,0 +1,28 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
KERNEL_LOADADDR := 0x80100000
define Device/Default
PROFILES := Default
BLOCKSIZE := 64k
FILESYSTEMS := squashfs
DEVICE_DTS_DIR := ../dts
KERNEL := kernel-bin | append-dtb | lzma | uImage lzma
KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | uImage lzma
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin = append-kernel | pad-to $$$$(BLOCKSIZE) | \
append-rootfs | pad-rootfs | append-metadata
endef
define Device/siflower_sf19a2890-evb
DEVICE_VENDOR := Siflower
DEVICE_MODEL := SF19A2890 EVB
BOARD_NAME := siflower,sf19a2890-evb
DEVICE_DTS := sf19a2890_evb
DEVICE_PACKAGES := kmod-switch-rtl8367b swconfig
endef
TARGET_DEVICES += siflower_sf19a2890-evb
$(eval $(call BuildImage))

View File

@ -0,0 +1,15 @@
define KernelPackage/phy-sf19a2890-usb
TITLE:=Siflower SF19A2890 USB 2.0 PHY Driver
KCONFIG:=CONFIG_PHY_SF19A2890_USB
DEPENDS:=@TARGET_siflower_sf19a2890
SUBMENU:=$(USB_MENU)
FILES:=$(LINUX_DIR)/drivers/phy/siflower/phy-sf19a2890-usb.ko
AUTOLOAD:=$(call AutoLoad,45,phy-sf19a2890-usb,1)
endef
define KernelPackage/phy-sf19a2890-usb/description
Support for Siflower SF19A2890 USB 2.0 PHY connected to the USB
controller.
endef
$(eval $(call KernelPackage,phy-sf19a2890-usb))

View File

@ -0,0 +1,59 @@
From c2ec4604afb39904c01dfe38ca8289c446b898bb Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:32:17 +0800
Subject: [PATCH 1/9] mips: add support for Siflower SF19A2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
arch/mips/Kconfig | 29 +++++++++++++++++++++++++++++
arch/mips/generic/Platform | 1 +
2 files changed, 30 insertions(+)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -861,6 +861,35 @@ config SIBYTE_BIGSUR
select ZONE_DMA32 if 64BIT
select SWIOTLB if ARCH_DMA_ADDR_T_64BIT && PCI
+config MACH_SIFLOWER_MIPS
+ bool "Siflower MIPS SoCs"
+ select MIPS_GENERIC
+ select ARM_AMBA
+ select BOOT_RAW
+ select CEVT_R4K
+ select CLKSRC_MIPS_GIC
+ select COMMON_CLK
+ select CPU_MIPSR2_IRQ_EI
+ select CPU_MIPSR2_IRQ_VI
+ select CSRC_R4K
+ select DMA_NONCOHERENT
+ select IRQ_MIPS_CPU
+ select MIPS_CPU_SCACHE
+ select MIPS_GIC
+ select MIPS_L1_CACHE_SHIFT_5
+ select NO_EXCEPT_FILL
+ select SMP_UP if SMP
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_MIPS16
+ select SYS_SUPPORTS_MIPS_CPS
+ select SYS_SUPPORTS_MULTITHREADING
+ select USE_OF
+ help
+ Select this to build a kernel which supports SoCs from Siflower
+ with MIPS InterAptiv cores, like Siflower SF19A2890.
+
config SNI_RM
bool "SNI RM200/300/400"
select ARC_MEMORY
--- a/arch/mips/generic/Platform
+++ b/arch/mips/generic/Platform
@@ -10,6 +10,7 @@
# Note: order matters, keep the asm/mach-generic include last.
cflags-$(CONFIG_MACH_INGENIC_SOC) += -I$(srctree)/arch/mips/include/asm/mach-ingenic
+cflags-$(CONFIG_MACH_SIFLOWER_MIPS) += -I$(srctree)/arch/mips/include/asm/mach-siflower
cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic
load-$(CONFIG_MIPS_GENERIC) += 0xffffffff80100000

View File

@ -0,0 +1,31 @@
From fcb96cb774abf14375326c41cedd237d6c8f6e94 Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:01 +0800
Subject: [PATCH 2/9] clk: add drivers for sf19a2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
2 files changed, 2 insertions(+)
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -489,6 +489,7 @@ source "drivers/clk/renesas/Kconfig"
source "drivers/clk/rockchip/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sifive/Kconfig"
+source "drivers/clk/siflower/Kconfig"
source "drivers/clk/socfpga/Kconfig"
source "drivers/clk/sprd/Kconfig"
source "drivers/clk/starfive/Kconfig"
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -116,6 +116,7 @@ obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
+obj-$(CONFIG_CLK_SIFLOWER) += siflower/
obj-y += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-y += sprd/

View File

@ -0,0 +1,38 @@
From 819d2a48d45f3734c876186e651917bae69be9ba Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:43 +0800
Subject: [PATCH 3/9] reset: add support for sf19a2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
drivers/reset/Kconfig | 8 ++++++++
drivers/reset/Makefile | 1 +
2 files changed, 9 insertions(+)
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -211,6 +211,14 @@ config RESET_SCMI
This driver uses SCMI Message Protocol to interact with the
firmware controlling all the reset signals.
+config RESET_SF19A2890_PERIPH
+ bool "Siflower SF19A2890 Peripheral Reset Controller Driver"
+ default MACH_SIFLOWER_MIPS
+ depends on HAS_IOMEM
+ help
+ This enables reset controller driver for peripheral reset blocks
+ found on Siflower SF19A2890 SoC.
+
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qc
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
+obj-$(CONFIG_RESET_SF19A2890_PERIPH) += reset-sf19a2890-periph.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o

View File

@ -0,0 +1,37 @@
From 1d37455eacb1d0c262ae6aaecadf27964cbf97d8 Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:57 +0800
Subject: [PATCH 4/9] gpio: add support for siflower socs
---
drivers/gpio/Kconfig | 8 ++++++++
drivers/gpio/Makefile | 1 +
2 files changed, 9 insertions(+)
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -576,6 +576,14 @@ config GPIO_SIFIVE
help
Say yes here to support the GPIO device on SiFive SoCs.
+config GPIO_SIFLOWER
+ tristate "SiFlower GPIO support"
+ depends on OF_GPIO
+ depends on MACH_SIFLOWER_MIPS || COMPILE_TEST
+ select GPIOLIB_IRQCHIP
+ help
+ GPIO controller driver for SiFlower SoCs.
+
config GPIO_SIOX
tristate "SIOX GPIO support"
depends on SIOX
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -143,6 +143,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o
+obj-$(CONFIG_GPIO_SIFLOWER) += gpio-siflower.o
obj-$(CONFIG_GPIO_SIM) += gpio-sim.o
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o

View File

@ -0,0 +1,39 @@
From 59c6a4972b584d986f72fe8d7c55930fdf799bc8 Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:34:20 +0800
Subject: [PATCH 5/9] pinctrl: add driver for siflower sf19a2890
---
drivers/pinctrl/Kconfig | 10 ++++++++++
drivers/pinctrl/Makefile | 1 +
2 files changed, 11 insertions(+)
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -417,6 +417,16 @@ config PINCTRL_ROCKCHIP
help
This support pinctrl and GPIO driver for Rockchip SoCs.
+config PINCTRL_SF19A2890
+ tristate "Siflower SF19A2890 pinctrl driver"
+ depends on OF && (MACH_SIFLOWER_MIPS || COMPILE_TEST)
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ default MACH_SIFLOWER_MIPS
+ help
+ Say Y here to enable the Siflower SF19A2890 pinctrl driver.
+
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-p
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
+obj-$(CONFIG_PINCTRL_SF19A2890) += pinctrl-sf19a2890.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o

View File

@ -0,0 +1,38 @@
From baa6c00f7a88b28f6838a9743f66c9f7f4716e25 Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:34:42 +0800
Subject: [PATCH 6/9] stmmac: add support for sf19a2890
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 9 +++++++++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
2 files changed, 10 insertions(+)
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -142,6 +142,15 @@ config DWMAC_ROCKCHIP
This selects the Rockchip RK3288 SoC glue layer support for
the stmmac device driver.
+config DWMAC_SF19A2890
+ tristate "Siflower SF19A2890 GMAC support"
+ default MACH_SIFLOWER_MIPS
+ help
+ Support for GMAC on Siflower SF19A2890 SoC.
+
+ This selects the Siflower SF19A2890 SoC glue layer support for
+ the stmmac device driver.
+
config DWMAC_SOCFPGA
tristate "SOCFPGA dwmac support"
default ARCH_INTEL_SOCFPGA
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-me
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
+obj-$(CONFIG_DWMAC_SF19A2890) += dwmac-sf19a2890.o
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
obj-$(CONFIG_DWMAC_STARFIVE) += dwmac-starfive.o
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o

View File

@ -0,0 +1,31 @@
From 68817a14ae9dff587cee8515e68c67cba89b39ab Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Mon, 9 Sep 2024 10:18:33 +0800
Subject: [PATCH 7/9] phy: add support for SF19A2890 USB PHY
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
2 files changed, 2 insertions(+)
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -90,6 +90,7 @@ source "drivers/phy/ralink/Kconfig"
source "drivers/phy/renesas/Kconfig"
source "drivers/phy/rockchip/Kconfig"
source "drivers/phy/samsung/Kconfig"
+source "drivers/phy/siflower/Kconfig"
source "drivers/phy/socionext/Kconfig"
source "drivers/phy/st/Kconfig"
source "drivers/phy/starfive/Kconfig"
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -29,6 +29,7 @@ obj-y += allwinner/ \
renesas/ \
rockchip/ \
samsung/ \
+ siflower/ \
socionext/ \
st/ \
starfive/ \

View File

@ -0,0 +1,36 @@
From 29282086f215ae723e6d2c139d23094e699ba5bb Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Mon, 9 Sep 2024 16:46:53 +0800
Subject: [PATCH 8/9] usb: dwc2: add support for Siflower SF19A2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
drivers/usb/dwc2/params.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -200,6 +200,14 @@ static void dwc2_set_amcc_params(struct
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
}
+static void dwc2_set_sf19a2890_params(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *p = &hsotg->params;
+
+ p->max_transfer_size = 65535;
+ p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
+}
+
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@@ -294,6 +302,8 @@ const struct of_device_id dwc2_of_match_
.data = dwc2_set_amlogic_a1_params },
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
{ .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
+ { .compatible = "siflower,sf19a2890-usb",
+ .data = dwc2_set_sf19a2890_params },
{ .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" },

View File

@ -0,0 +1,67 @@
From 0b04c37a1aae523025195c29a6477cf26234d26c Mon Sep 17 00:00:00 2001
From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 10 Sep 2024 09:10:27 +0800
Subject: [PATCH 9/9] usb: dwc2: handle OTG interrupt regardless of GINTSTS
The DWC OTG 3.30a found on Siflower SF19A2890 has battery charger
support enabled. It triggers MultVallpChng interrupt (bit 20 of
GOTGINT) but doesn't set OTGInt in GINTSTS. As a result, this
interrupt is never handled, and linux disables USB interrupt
because "nobody cares".
Handle OTG interrupt in IRQ handler regardless of whether the
OTGInt bit in GINTSTS is set or not.
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
drivers/usb/dwc2/core_intr.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -79,7 +79,7 @@ static void dwc2_handle_mode_mismatch_in
*
* @hsotg: Programming view of DWC_otg controller
*/
-static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
+static irqreturn_t dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
{
u32 gotgint;
u32 gotgctl;
@@ -87,6 +87,10 @@ static void dwc2_handle_otg_intr(struct
gotgint = dwc2_readl(hsotg, GOTGINT);
gotgctl = dwc2_readl(hsotg, GOTGCTL);
+
+ if (!gotgint)
+ return IRQ_NONE;
+
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
dwc2_op_state_str(hsotg));
@@ -229,6 +233,7 @@ static void dwc2_handle_otg_intr(struct
/* Clear GOTGINT */
dwc2_writel(hsotg, gotgint, GOTGINT);
+ return IRQ_HANDLED;
}
/**
@@ -842,6 +847,8 @@ irqreturn_t dwc2_handle_common_intr(int
hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
& HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
+ retval = dwc2_handle_otg_intr(hsotg);
+
gintsts = dwc2_read_common_intr(hsotg);
if (gintsts & ~GINTSTS_PRTINT)
retval = IRQ_HANDLED;
@@ -855,8 +862,6 @@ irqreturn_t dwc2_handle_common_intr(int
if (gintsts & GINTSTS_MODEMIS)
dwc2_handle_mode_mismatch_intr(hsotg);
- if (gintsts & GINTSTS_OTGINT)
- dwc2_handle_otg_intr(hsotg);
if (gintsts & GINTSTS_CONIDSTSCHNG)
dwc2_handle_conn_id_status_change_intr(hsotg);
if (gintsts & GINTSTS_DISCONNINT)

View File

@ -0,0 +1,42 @@
. /lib/functions.sh
. /lib/functions/uci-defaults.sh
. /lib/functions/system.sh
siflower_setup_interfaces()
{
local board="$1"
case $board in
siflower,sf19a2890-evb)
ucidef_add_switch "switch0" \
"0:wan" "1:lan" "2:lan" "3:lan" "4:lan" "6@eth0"
;;
esac
}
siflower_setup_macs()
{
local board="$1"
local lan_mac=""
local wan_mac=""
local label_mac=""
case $board in
siflower,sf19a2890-evb)
wan_mac=$(macaddr_add "$(mtd_get_mac_binary factory 0x0)" 1)
;;
esac
[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
[ -n "$label_mac" ] && ucidef_set_label_macaddr $label_mac
}
board_config_update
board=$(board_name)
siflower_setup_interfaces $board
siflower_setup_macs $board
board_config_flush
exit 0

View File

@ -0,0 +1,22 @@
PART_NAME=firmware
REQUIRE_IMAGE_METADATA=1
platform_check_image() {
local board=$(board_name)
case "$board" in
*)
return 0
;;
esac
}
platform_do_upgrade() {
local board=$(board_name)
case "$board" in
*)
default_do_upgrade "$1"
;;
esac
}

View File

@ -0,0 +1,266 @@
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARM_AMBA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BOARD_SCACHE=y
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
CONFIG_CC_NO_ARRAY_BOUNDS=y
CONFIG_CEVT_R4K=y
CONFIG_CLKSRC_MIPS_GIC=y
CONFIG_CLK_SF19A2890=y
CONFIG_CLK_SF19A2890_PERIPH=y
CONFIG_CLK_SIFLOWER=y
CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CONNECTOR=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y
CONFIG_COREDUMP=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_DIEI=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_CPU_MITIGATIONS=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRC16=y
CONFIG_CRC_CCITT=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_REDUCED=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
# CONFIG_DWMAC_GENERIC is not set
CONFIG_DWMAC_SF19A2890=y
CONFIG_DW_WATCHDOG=y
CONFIG_ELF_CORE=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
CONFIG_FANOTIFY=y
CONFIG_FHANDLE=y
CONFIG_FIXED_PHY=y
CONFIG_FS_IOMAP=y
CONFIG_FUNCTION_ALIGNMENT=0
CONFIG_FWNODE_MDIO=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
CONFIG_GCC10_NO_ARRAY_BOUNDS=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_LIB_ASHLDI3=y
CONFIG_GENERIC_LIB_ASHRDI3=y
CONFIG_GENERIC_LIB_CMPDI2=y
CONFIG_GENERIC_LIB_LSHRDI3=y
CONFIG_GENERIC_LIB_UCMPDI2=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_SIFLOWER=y
CONFIG_GRO_CELLS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HOTPLUG_CORE_SYNC=y
CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
CONFIG_HOTPLUG_CPU=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MACH_SIFLOWER_MIPS=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MFD_SYSCON=y
CONFIG_MICREL_PHY=y
CONFIG_MIGRATION=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
CONFIG_MIPS_CM=y
CONFIG_MIPS_CMDLINE_DTB_EXTEND=y
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CPC=y
CONFIG_MIPS_CPS=y
# CONFIG_MIPS_CPS_NS16550_BOOL is not set
CONFIG_MIPS_CPS_PM=y
CONFIG_MIPS_CPU_SCACHE=y
CONFIG_MIPS_FP_SUPPORT=y
CONFIG_MIPS_GENERIC=y
CONFIG_MIPS_GIC=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_L1_CACHE_SHIFT_5=y
CONFIG_MIPS_MT=y
CONFIG_MIPS_MT_FPAFF=y
CONFIG_MIPS_MT_SMP=y
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_NR_CPU_NR_MAP=4
CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
CONFIG_MMU_LAZY_TLB_REFCOUNT=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SRCU_NMI_SAFE=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_INGRESS=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_XGRESS=y
CONFIG_NLS=y
CONFIG_NO_EXCEPT_FILL=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_NVMEM=y
CONFIG_NVMEM_LAYOUTS=y
CONFIG_NVMEM_SYSFS=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_PADATA=y
CONFIG_PAGE_POOL=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PCS_XPCS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLIB_LEDS=y
CONFIG_PHYLINK=y
# CONFIG_PHY_SF19A2890_USB is not set
CONFIG_PINCTRL=y
CONFIG_PINCTRL_SF19A2890=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_POWER_SUPPLY=y
CONFIG_PPS=y
CONFIG_PREEMPT_NONE_BUILD=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_EVENTS=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RANDSTRUCT_NONE=y
CONFIG_RATIONAL=y
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RESET_SF19A2890_PERIPH=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_SCHEDSTATS=y
CONFIG_SCHED_INFO=y
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SMP=y
CONFIG_SMP_UP=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_PL022=y
CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
CONFIG_SRAM=y
CONFIG_STACKPROTECTOR=y
CONFIG_STMMAC_ETH=y
CONFIG_STMMAC_PLATFORM=y
CONFIG_SWPHY=y
CONFIG_SYNC_R4K=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MIPS_CPS=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_SYS_SUPPORTS_SCHED_SMT=y
CONFIG_SYS_SUPPORTS_SMP=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WEAK_ORDERING=y
CONFIG_WERROR=y
CONFIG_XPS=y

View File

@ -0,0 +1,12 @@
ARCH:=mipsel
SUBTARGET:=sf19a2890
BOARDNAME:=Siflower SF19A2890 based boards
FEATURES+=fpu
CPU_TYPE:=24kc
CPU_SUBTYPE:=24kf
KERNELNAME:=vmlinux
define Target/Description
Build firmware images for Siflower SF19A2890 based boards.
endef