From 1b77de4476637a614d23b34bcfae0b788409389c Mon Sep 17 00:00:00 2001 From: "Horatiu.Vultur@microchip.com" Date: Mon, 25 Feb 2019 10:59:54 +0000 Subject: [PATCH 01/10] spi: designware: Change include order With current order of include files, the file designware_spi.c can't see that the struct global_data has the member board_type when CONFIG_BOARD_TYPES is defined. By not seeing this then all the members are shifted in the struct global_data. So when the driver is trying to read from device tree blob, it would pass the wrong address to the function 'fdtdev_get_int'. This will make to use the default frequency 500000. The fix consists of changing the order of include files in designware_spi.c to include first common.h file. Signed-off-by: Horatiu Vultur Reviewed-by: Jagan Teki --- drivers/spi/designware_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 02d93763d4..dadb6fa18b 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -9,8 +9,8 @@ * Copyright (c) 2009, Intel Corporation. */ -#include #include +#include #include #include #include From 6cb6aa602b541d2b2f864c47b6a3f62e3eefe282 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:05 +0530 Subject: [PATCH 02/10] spi: sun4i: Poll for rxfifo to be filled up To drain rx fifo the fifo need to poll for how much data has been filled up in rx fifo. To achieve this, the current code is using wait_for_bit logic on control register with exchange burst mode mask, which is not a proper way of waiting for fifo filled up. So, add code for polling rxfifo to be filled up using fifo status register. Signed-off-by: Jagan Teki Reviewed-by: Andre Przywara --- drivers/spi/sun4i_spi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index 38cc743c61..f5f2d5635a 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -31,6 +31,8 @@ #include +#include + #define SUN4I_FIFO_DEPTH 64 #define SUN4I_RXDATA_REG 0x00 @@ -46,7 +48,6 @@ #define SUN4I_CTL_LMTF BIT(6) #define SUN4I_CTL_TF_RST BIT(8) #define SUN4I_CTL_RF_RST BIT(9) -#define SUN4I_CTL_XCH_MASK 0x0400 #define SUN4I_CTL_XCH BIT(10) #define SUN4I_CTL_CS_MASK 0x3000 #define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK) @@ -308,7 +309,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); u32 len = bitlen / 8; - u32 reg; + u32 reg, rx_fifocnt; u8 nbytes; int ret; @@ -343,10 +344,12 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, reg = readl(&priv->regs->ctl); writel(reg | SUN4I_CTL_XCH, &priv->regs->ctl); - /* Wait transfer to complete */ - ret = wait_for_bit_le32(&priv->regs->ctl, SUN4I_CTL_XCH_MASK, - false, SUN4I_SPI_TIMEOUT_US, false); - if (ret) { + /* Wait till RX FIFO to be empty */ + ret = readl_poll_timeout(&priv->regs->fifo_sta, rx_fifocnt, + (((rx_fifocnt & SUN4I_FIFO_STA_RF_CNT_MASK) >> + SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes), + SUN4I_SPI_TIMEOUT_US); + if (ret < 0) { printf("ERROR: sun4i_spi: Timeout transferring data\n"); sun4i_spi_set_cs(bus, slave_plat->cs, false); return ret; From 82111469a5451adeb14413dc744c96f1bf13c758 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:06 +0530 Subject: [PATCH 03/10] clk: sunxi: Implement SPI clocks, resets - Implement SPI AHB, MOD clocks via ccu_clk_gate for all supported Allwinner SoCs - Implement SPI resets via ccu_reset for all supported Allwinner SoCs. Signed-off-by: Jagan Teki Reviewed-by: Andre Przywara --- drivers/clk/sunxi/clk_a10.c | 10 ++++++++++ drivers/clk/sunxi/clk_a10s.c | 7 +++++++ drivers/clk/sunxi/clk_a23.c | 7 +++++++ drivers/clk/sunxi/clk_a31.c | 13 +++++++++++++ drivers/clk/sunxi/clk_a64.c | 7 +++++++ drivers/clk/sunxi/clk_a80.c | 13 +++++++++++++ drivers/clk/sunxi/clk_a83t.c | 7 +++++++ drivers/clk/sunxi/clk_h3.c | 7 +++++++ drivers/clk/sunxi/clk_h6.c | 9 +++++++++ drivers/clk/sunxi/clk_r40.c | 13 +++++++++++++ drivers/clk/sunxi/clk_v3s.c | 4 ++++ 11 files changed, 97 insertions(+) diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c index 2aa41efe17..b8b57e2b31 100644 --- a/drivers/clk/sunxi/clk_a10.c +++ b/drivers/clk/sunxi/clk_a10.c @@ -22,6 +22,10 @@ static struct ccu_clk_gate a10_gates[] = { [CLK_AHB_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB_MMC2] = GATE(0x060, BIT(10)), [CLK_AHB_MMC3] = GATE(0x060, BIT(11)), + [CLK_AHB_SPI0] = GATE(0x060, BIT(20)), + [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), + [CLK_AHB_SPI2] = GATE(0x060, BIT(22)), + [CLK_AHB_SPI3] = GATE(0x060, BIT(23)), [CLK_APB1_UART0] = GATE(0x06c, BIT(16)), [CLK_APB1_UART1] = GATE(0x06c, BIT(17)), @@ -32,9 +36,15 @@ static struct ccu_clk_gate a10_gates[] = { [CLK_APB1_UART6] = GATE(0x06c, BIT(22)), [CLK_APB1_UART7] = GATE(0x06c, BIT(23)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_SPI2] = GATE(0x0a8, BIT(31)), + [CLK_USB_OHCI0] = GATE(0x0cc, BIT(6)), [CLK_USB_OHCI1] = GATE(0x0cc, BIT(7)), [CLK_USB_PHY] = GATE(0x0cc, BIT(8)), + + [CLK_SPI3] = GATE(0x0d4, BIT(31)), }; static struct ccu_reset a10_resets[] = { diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c index 87b74e52dc..c6fcede822 100644 --- a/drivers/clk/sunxi/clk_a10s.c +++ b/drivers/clk/sunxi/clk_a10s.c @@ -19,12 +19,19 @@ static struct ccu_clk_gate a10s_gates[] = { [CLK_AHB_MMC0] = GATE(0x060, BIT(8)), [CLK_AHB_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB_MMC2] = GATE(0x060, BIT(10)), + [CLK_AHB_SPI0] = GATE(0x060, BIT(20)), + [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), + [CLK_AHB_SPI2] = GATE(0x060, BIT(22)), [CLK_APB1_UART0] = GATE(0x06c, BIT(16)), [CLK_APB1_UART1] = GATE(0x06c, BIT(17)), [CLK_APB1_UART2] = GATE(0x06c, BIT(18)), [CLK_APB1_UART3] = GATE(0x06c, BIT(19)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_SPI2] = GATE(0x0a8, BIT(31)), + [CLK_USB_OHCI] = GATE(0x0cc, BIT(6)), [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c index 1ef2359286..c16019215e 100644 --- a/drivers/clk/sunxi/clk_a23.c +++ b/drivers/clk/sunxi/clk_a23.c @@ -16,6 +16,8 @@ static struct ccu_clk_gate a23_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)), [CLK_BUS_EHCI] = GATE(0x060, BIT(26)), [CLK_BUS_OHCI] = GATE(0x060, BIT(29)), @@ -26,6 +28,9 @@ static struct ccu_clk_gate a23_gates[] = { [CLK_BUS_UART3] = GATE(0x06c, BIT(19)), [CLK_BUS_UART4] = GATE(0x06c, BIT(20)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)), @@ -41,6 +46,8 @@ static struct ccu_reset a23_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(24)), [RST_BUS_EHCI] = RESET(0x2c0, BIT(26)), [RST_BUS_OHCI] = RESET(0x2c0, BIT(29)), diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c index 5bd8b7dccc..fa6e3eeef0 100644 --- a/drivers/clk/sunxi/clk_a31.c +++ b/drivers/clk/sunxi/clk_a31.c @@ -17,6 +17,10 @@ static struct ccu_clk_gate a31_gates[] = { [CLK_AHB1_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB1_MMC2] = GATE(0x060, BIT(10)), [CLK_AHB1_MMC3] = GATE(0x060, BIT(11)), + [CLK_AHB1_SPI0] = GATE(0x060, BIT(20)), + [CLK_AHB1_SPI1] = GATE(0x060, BIT(21)), + [CLK_AHB1_SPI2] = GATE(0x060, BIT(22)), + [CLK_AHB1_SPI3] = GATE(0x060, BIT(23)), [CLK_AHB1_OTG] = GATE(0x060, BIT(24)), [CLK_AHB1_EHCI0] = GATE(0x060, BIT(26)), [CLK_AHB1_EHCI1] = GATE(0x060, BIT(27)), @@ -31,6 +35,11 @@ static struct ccu_clk_gate a31_gates[] = { [CLK_APB2_UART4] = GATE(0x06c, BIT(20)), [CLK_APB2_UART5] = GATE(0x06c, BIT(21)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_SPI2] = GATE(0x0a8, BIT(31)), + [CLK_SPI3] = GATE(0x0ac, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)), @@ -48,6 +57,10 @@ static struct ccu_reset a31_resets[] = { [RST_AHB1_MMC1] = RESET(0x2c0, BIT(9)), [RST_AHB1_MMC2] = RESET(0x2c0, BIT(10)), [RST_AHB1_MMC3] = RESET(0x2c0, BIT(11)), + [RST_AHB1_SPI0] = RESET(0x2c0, BIT(20)), + [RST_AHB1_SPI1] = RESET(0x2c0, BIT(21)), + [RST_AHB1_SPI2] = RESET(0x2c0, BIT(22)), + [RST_AHB1_SPI3] = RESET(0x2c0, BIT(23)), [RST_AHB1_OTG] = RESET(0x2c0, BIT(24)), [RST_AHB1_EHCI0] = RESET(0x2c0, BIT(26)), [RST_AHB1_EHCI1] = RESET(0x2c0, BIT(27)), diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c index 910275fbce..322d6cd557 100644 --- a/drivers/clk/sunxi/clk_a64.c +++ b/drivers/clk/sunxi/clk_a64.c @@ -16,6 +16,8 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(23)), [CLK_BUS_EHCI0] = GATE(0x060, BIT(24)), [CLK_BUS_EHCI1] = GATE(0x060, BIT(25)), @@ -28,6 +30,9 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_UART3] = GATE(0x06c, BIT(19)), [CLK_BUS_UART4] = GATE(0x06c, BIT(20)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)), @@ -44,6 +49,8 @@ static const struct ccu_reset a64_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(23)), [RST_BUS_EHCI0] = RESET(0x2c0, BIT(24)), [RST_BUS_EHCI1] = RESET(0x2c0, BIT(25)), diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c index aec1d80c46..fb76aad528 100644 --- a/drivers/clk/sunxi/clk_a80.c +++ b/drivers/clk/sunxi/clk_a80.c @@ -13,7 +13,16 @@ #include static const struct ccu_clk_gate a80_gates[] = { + [CLK_SPI0] = GATE(0x430, BIT(31)), + [CLK_SPI1] = GATE(0x434, BIT(31)), + [CLK_SPI2] = GATE(0x438, BIT(31)), + [CLK_SPI3] = GATE(0x43c, BIT(31)), + [CLK_BUS_MMC] = GATE(0x580, BIT(8)), + [CLK_BUS_SPI0] = GATE(0x580, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x580, BIT(21)), + [CLK_BUS_SPI2] = GATE(0x580, BIT(22)), + [CLK_BUS_SPI3] = GATE(0x580, BIT(23)), [CLK_BUS_UART0] = GATE(0x594, BIT(16)), [CLK_BUS_UART1] = GATE(0x594, BIT(17)), @@ -25,6 +34,10 @@ static const struct ccu_clk_gate a80_gates[] = { static const struct ccu_reset a80_resets[] = { [RST_BUS_MMC] = RESET(0x5a0, BIT(8)), + [RST_BUS_SPI0] = RESET(0x5a0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x5a0, BIT(21)), + [RST_BUS_SPI2] = RESET(0x5a0, BIT(22)), + [RST_BUS_SPI3] = RESET(0x5a0, BIT(23)), [RST_BUS_UART0] = RESET(0x5b4, BIT(16)), [RST_BUS_UART1] = RESET(0x5b4, BIT(17)), diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c index b5a555da36..36f7e14c45 100644 --- a/drivers/clk/sunxi/clk_a83t.c +++ b/drivers/clk/sunxi/clk_a83t.c @@ -16,6 +16,8 @@ static struct ccu_clk_gate a83t_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)), [CLK_BUS_EHCI0] = GATE(0x060, BIT(26)), [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)), @@ -27,6 +29,9 @@ static struct ccu_clk_gate a83t_gates[] = { [CLK_BUS_UART3] = GATE(0x06c, BIT(19)), [CLK_BUS_UART4] = GATE(0x06c, BIT(20)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_HSIC] = GATE(0x0cc, BIT(10)), @@ -42,6 +47,8 @@ static struct ccu_reset a83t_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(24)), [RST_BUS_EHCI0] = RESET(0x2c0, BIT(26)), [RST_BUS_EHCI1] = RESET(0x2c0, BIT(27)), diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c index 416aec2b89..5f99ef7342 100644 --- a/drivers/clk/sunxi/clk_h3.c +++ b/drivers/clk/sunxi/clk_h3.c @@ -16,6 +16,8 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(23)), [CLK_BUS_EHCI0] = GATE(0x060, BIT(24)), [CLK_BUS_EHCI1] = GATE(0x060, BIT(25)), @@ -31,6 +33,9 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), [CLK_BUS_UART3] = GATE(0x06c, BIT(19)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)), @@ -50,6 +55,8 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(23)), [RST_BUS_EHCI0] = RESET(0x2c0, BIT(24)), [RST_BUS_EHCI1] = RESET(0x2c0, BIT(25)), diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c index 902612da91..71f0c78656 100644 --- a/drivers/clk/sunxi/clk_h6.c +++ b/drivers/clk/sunxi/clk_h6.c @@ -20,6 +20,12 @@ static struct ccu_clk_gate h6_gates[] = { [CLK_BUS_UART1] = GATE(0x90c, BIT(1)), [CLK_BUS_UART2] = GATE(0x90c, BIT(2)), [CLK_BUS_UART3] = GATE(0x90c, BIT(3)), + + [CLK_SPI0] = GATE(0x940, BIT(31)), + [CLK_SPI1] = GATE(0x944, BIT(31)), + + [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)), + [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)), }; static struct ccu_reset h6_resets[] = { @@ -30,6 +36,9 @@ static struct ccu_reset h6_resets[] = { [RST_BUS_UART1] = RESET(0x90c, BIT(17)), [RST_BUS_UART2] = RESET(0x90c, BIT(18)), [RST_BUS_UART3] = RESET(0x90c, BIT(19)), + + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), + [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), }; static const struct ccu_desc h6_ccu_desc = { diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c index b9457e1971..92907281f1 100644 --- a/drivers/clk/sunxi/clk_r40.c +++ b/drivers/clk/sunxi/clk_r40.c @@ -17,6 +17,10 @@ static struct ccu_clk_gate r40_gates[] = { [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), [CLK_BUS_MMC3] = GATE(0x060, BIT(11)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), + [CLK_BUS_SPI2] = GATE(0x060, BIT(22)), + [CLK_BUS_SPI3] = GATE(0x060, BIT(23)), [CLK_BUS_OTG] = GATE(0x060, BIT(25)), [CLK_BUS_EHCI0] = GATE(0x060, BIT(26)), [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)), @@ -34,6 +38,11 @@ static struct ccu_clk_gate r40_gates[] = { [CLK_BUS_UART6] = GATE(0x06c, BIT(22)), [CLK_BUS_UART7] = GATE(0x06c, BIT(23)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_SPI1] = GATE(0x0a4, BIT(31)), + [CLK_SPI2] = GATE(0x0a8, BIT(31)), + [CLK_SPI3] = GATE(0x0ac, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), [CLK_USB_PHY1] = GATE(0x0cc, BIT(9)), [CLK_USB_PHY2] = GATE(0x0cc, BIT(10)), @@ -51,6 +60,10 @@ static struct ccu_reset r40_resets[] = { [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), [RST_BUS_MMC3] = RESET(0x2c0, BIT(11)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), + [RST_BUS_SPI2] = RESET(0x2c0, BIT(22)), + [RST_BUS_SPI3] = RESET(0x2c0, BIT(23)), [RST_BUS_OTG] = RESET(0x2c0, BIT(25)), [RST_BUS_EHCI0] = RESET(0x2c0, BIT(26)), [RST_BUS_EHCI1] = RESET(0x2c0, BIT(27)), diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c index c8a9027889..789ac72026 100644 --- a/drivers/clk/sunxi/clk_v3s.c +++ b/drivers/clk/sunxi/clk_v3s.c @@ -16,12 +16,15 @@ static struct ccu_clk_gate v3s_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), + [CLK_USB_PHY0] = GATE(0x0cc, BIT(8)), }; @@ -31,6 +34,7 @@ static struct ccu_reset v3s_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_OTG] = RESET(0x2c0, BIT(24)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), From 8cbf09ba1cfdc7b47ead3ff330e9a7bc57bda4ab Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:07 +0530 Subject: [PATCH 04/10] spi: sun4i: Simplify reg writes using set/clrbits_le32 Update the existing register writes using setbits_le32 and clrbits_le32 in required places. Signed-off-by: Jagan Teki --- drivers/spi/sun4i_spi.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index f5f2d5635a..0b1663038c 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -283,20 +283,18 @@ static int sun4i_spi_claim_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); - writel(SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP | - SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW, - &priv->regs->ctl); + setbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE | + SUN4I_CTL_MASTER | SUN4I_CTL_TP | + SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW); + return 0; } static int sun4i_spi_release_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); - u32 reg; - reg = readl(&priv->regs->ctl); - reg &= ~SUN4I_CTL_ENABLE; - writel(reg, &priv->regs->ctl); + clrbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE); return 0; } @@ -309,7 +307,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); u32 len = bitlen / 8; - u32 reg, rx_fifocnt; + u32 rx_fifocnt; u8 nbytes; int ret; @@ -324,10 +322,8 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) sun4i_spi_set_cs(bus, slave_plat->cs, true); - reg = readl(&priv->regs->ctl); - /* Reset FIFOs */ - writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->ctl); + setbits_le32(&priv->regs->ctl, SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); while (len) { /* Setup the transfer now... */ @@ -341,8 +337,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, sun4i_spi_fill_fifo(priv, nbytes); /* Start the transfer */ - reg = readl(&priv->regs->ctl); - writel(reg | SUN4I_CTL_XCH, &priv->regs->ctl); + setbits_le32(&priv->regs->ctl, SUN4I_CTL_XCH); /* Wait till RX FIFO to be empty */ ret = readl_poll_timeout(&priv->regs->fifo_sta, rx_fifocnt, From 8d9bf46847cd66989d944060d9ad4b37bb2bc460 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:08 +0530 Subject: [PATCH 05/10] spi: sun4i: Access registers and bits via enum offsets Allwinner support two different SPI controllers one for A10 and another for A31 with minimal changes in register offsets and respective register bits, but the logic for accessing the SPI master via SPI slave remains nearly similar. Add enum offsets for register set and register bits, so-that it can access both classes of SPI controllers. Assign same control register for global, transfer and fifo control registers to make the same code compatible with A31 SPI controller. Signed-off-by: Jagan Teki Tested-by: Stefan Mavrodiev # A20-SOM204 --- drivers/spi/sun4i_spi.c | 154 +++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 42 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index 0b1663038c..be026e6554 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -83,7 +83,6 @@ #define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) #define SUN4I_FIFO_STA_REG 0x28 -#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f #define SUN4I_FIFO_STA_RF_CNT_BITS 0 #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f #define SUN4I_FIFO_STA_TF_CNT_BITS 16 @@ -93,28 +92,56 @@ #define SUN4I_SPI_DEFAULT_RATE 1000000 #define SUN4I_SPI_TIMEOUT_US 1000000 -/* sun4i spi register set */ -struct sun4i_spi_regs { - u32 rxdata; - u32 txdata; - u32 ctl; - u32 intctl; - u32 st; - u32 dmactl; - u32 wait; - u32 cctl; - u32 bc; - u32 tc; - u32 fifo_sta; +#define SPI_REG(priv, reg) ((priv)->base_addr + \ + (priv)->variant->regs[reg]) +#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit]) +#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \ + SPI_BIT(priv, SPI_TCR_CS_MASK)) + +/* sun spi register set */ +enum sun4i_spi_regs { + SPI_GCR, + SPI_TCR, + SPI_FCR, + SPI_FSR, + SPI_CCR, + SPI_BC, + SPI_TC, + SPI_BCTL, + SPI_TXD, + SPI_RXD, +}; + +/* sun spi register bits */ +enum sun4i_spi_bits { + SPI_GCR_TP, + SPI_TCR_CPHA, + SPI_TCR_CPOL, + SPI_TCR_CS_ACTIVE_LOW, + SPI_TCR_CS_SEL, + SPI_TCR_CS_MASK, + SPI_TCR_XCH, + SPI_TCR_CS_MANUAL, + SPI_TCR_CS_LEVEL, + SPI_FCR_TF_RST, + SPI_FCR_RF_RST, + SPI_FSR_RF_CNT_MASK, +}; + +struct sun4i_spi_variant { + const unsigned long *regs; + const u32 *bits; }; struct sun4i_spi_platdata { + struct sun4i_spi_variant *variant; u32 base_addr; u32 max_hz; }; struct sun4i_spi_priv { - struct sun4i_spi_regs *regs; + struct sun4i_spi_variant *variant; + u32 base_addr; u32 freq; u32 mode; @@ -129,7 +156,7 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len) u8 byte; while (len--) { - byte = readb(&priv->regs->rxdata); + byte = readb(SPI_REG(priv, SPI_RXD)); if (priv->rx_buf) *priv->rx_buf++ = byte; } @@ -141,7 +168,7 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len) while (len--) { byte = priv->tx_buf ? *priv->tx_buf++ : 0; - writeb(byte, &priv->regs->txdata); + writeb(byte, SPI_REG(priv, SPI_TXD)); } } @@ -150,17 +177,17 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable) struct sun4i_spi_priv *priv = dev_get_priv(bus); u32 reg; - reg = readl(&priv->regs->ctl); + reg = readl(SPI_REG(priv, SPI_TCR)); - reg &= ~SUN4I_CTL_CS_MASK; - reg |= SUN4I_CTL_CS(cs); + reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK); + reg |= SPI_CS(priv, cs); if (enable) - reg &= ~SUN4I_CTL_CS_LEVEL; + reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL); else - reg |= SUN4I_CTL_CS_LEVEL; + reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL); - writel(reg, &priv->regs->ctl); + writel(reg, SPI_REG(priv, SPI_TCR)); } static int sun4i_spi_parse_pins(struct udevice *dev) @@ -255,6 +282,7 @@ static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) int node = dev_of_offset(bus); plat->base_addr = devfdt_get_addr(bus); + plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus); plat->max_hz = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", SUN4I_SPI_DEFAULT_RATE); @@ -273,7 +301,8 @@ static int sun4i_spi_probe(struct udevice *bus) sun4i_spi_enable_clock(); sun4i_spi_parse_pins(bus); - priv->regs = (struct sun4i_spi_regs *)(uintptr_t)plat->base_addr; + priv->variant = plat->variant; + priv->base_addr = plat->base_addr; priv->freq = plat->max_hz; return 0; @@ -283,9 +312,11 @@ static int sun4i_spi_claim_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); - setbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE | - SUN4I_CTL_MASTER | SUN4I_CTL_TP | - SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW); + setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE | + SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP)); + + setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) | + SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW)); return 0; } @@ -294,7 +325,7 @@ static int sun4i_spi_release_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); - clrbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE); + clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE); return 0; } @@ -323,25 +354,29 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, sun4i_spi_set_cs(bus, slave_plat->cs, true); /* Reset FIFOs */ - setbits_le32(&priv->regs->ctl, SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); + setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) | + SPI_BIT(priv, SPI_FCR_TF_RST)); while (len) { /* Setup the transfer now... */ nbytes = min(len, (u32)(SUN4I_FIFO_DEPTH - 1)); /* Setup the counters */ - writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bc); - writel(SUN4I_XMIT_CNT(nbytes), &priv->regs->tc); + writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC)); + writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC)); /* Fill the TX FIFO */ sun4i_spi_fill_fifo(priv, nbytes); /* Start the transfer */ - setbits_le32(&priv->regs->ctl, SUN4I_CTL_XCH); + setbits_le32(SPI_REG(priv, SPI_TCR), + SPI_BIT(priv, SPI_TCR_XCH)); /* Wait till RX FIFO to be empty */ - ret = readl_poll_timeout(&priv->regs->fifo_sta, rx_fifocnt, - (((rx_fifocnt & SUN4I_FIFO_STA_RF_CNT_MASK) >> + ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR), + rx_fifocnt, + (((rx_fifocnt & + SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >> SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes), SUN4I_SPI_TIMEOUT_US); if (ret < 0) { @@ -390,7 +425,7 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint speed) */ div = SUN4I_SPI_MAX_RATE / (2 * speed); - reg = readl(&priv->regs->cctl); + reg = readl(SPI_REG(priv, SPI_CCR)); if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { if (div > 0) @@ -405,7 +440,7 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint speed) } priv->freq = speed; - writel(reg, &priv->regs->cctl); + writel(reg, SPI_REG(priv, SPI_CCR)); return 0; } @@ -415,17 +450,17 @@ static int sun4i_spi_set_mode(struct udevice *dev, uint mode) struct sun4i_spi_priv *priv = dev_get_priv(dev); u32 reg; - reg = readl(&priv->regs->ctl); - reg &= ~(SUN4I_CTL_CPOL | SUN4I_CTL_CPHA); + reg = readl(SPI_REG(priv, SPI_TCR)); + reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA)); if (mode & SPI_CPOL) - reg |= SUN4I_CTL_CPOL; + reg |= SPI_BIT(priv, SPI_TCR_CPOL); if (mode & SPI_CPHA) - reg |= SUN4I_CTL_CPHA; + reg |= SPI_BIT(priv, SPI_TCR_CPHA); priv->mode = mode; - writel(reg, &priv->regs->ctl); + writel(reg, SPI_REG(priv, SPI_TCR)); return 0; } @@ -438,8 +473,43 @@ static const struct dm_spi_ops sun4i_spi_ops = { .set_mode = sun4i_spi_set_mode, }; +static const unsigned long sun4i_spi_regs[] = { + [SPI_GCR] = SUN4I_CTL_REG, + [SPI_TCR] = SUN4I_CTL_REG, + [SPI_FCR] = SUN4I_CTL_REG, + [SPI_FSR] = SUN4I_FIFO_STA_REG, + [SPI_CCR] = SUN4I_CLK_CTL_REG, + [SPI_BC] = SUN4I_BURST_CNT_REG, + [SPI_TC] = SUN4I_XMIT_CNT_REG, + [SPI_TXD] = SUN4I_TXDATA_REG, + [SPI_RXD] = SUN4I_RXDATA_REG, +}; + +static const u32 sun4i_spi_bits[] = { + [SPI_GCR_TP] = BIT(18), + [SPI_TCR_CPHA] = BIT(2), + [SPI_TCR_CPOL] = BIT(3), + [SPI_TCR_CS_ACTIVE_LOW] = BIT(4), + [SPI_TCR_XCH] = BIT(10), + [SPI_TCR_CS_SEL] = 12, + [SPI_TCR_CS_MASK] = 0x3000, + [SPI_TCR_CS_MANUAL] = BIT(16), + [SPI_TCR_CS_LEVEL] = BIT(17), + [SPI_FCR_TF_RST] = BIT(8), + [SPI_FCR_RF_RST] = BIT(9), + [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0), +}; + +static const struct sun4i_spi_variant sun4i_a10_spi_variant = { + .regs = sun4i_spi_regs, + .bits = sun4i_spi_bits, +}; + static const struct udevice_id sun4i_spi_ids[] = { - { .compatible = "allwinner,sun4i-a10-spi" }, + { + .compatible = "allwinner,sun4i-a10-spi", + .data = (ulong)&sun4i_a10_spi_variant, + }, { } }; From 178fbd243daeb0a3137e46bdc3b63d8df049e982 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:09 +0530 Subject: [PATCH 06/10] spi: sun4i: Support fifo_depth via drvdata Support fifo_depth via drvdata instead of macro definition, this would eventually reduce another macro definition for new SPI controller fifo depth support addition. Signed-off-by: Jagan Teki Reviewed-by: Andre Przywara --- drivers/spi/sun4i_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index be026e6554..82e69a6b6a 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -33,8 +33,6 @@ #include -#define SUN4I_FIFO_DEPTH 64 - #define SUN4I_RXDATA_REG 0x00 #define SUN4I_TXDATA_REG 0x04 @@ -131,6 +129,7 @@ enum sun4i_spi_bits { struct sun4i_spi_variant { const unsigned long *regs; const u32 *bits; + u32 fifo_depth; }; struct sun4i_spi_platdata { @@ -359,7 +358,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, while (len) { /* Setup the transfer now... */ - nbytes = min(len, (u32)(SUN4I_FIFO_DEPTH - 1)); + nbytes = min(len, (priv->variant->fifo_depth - 1)); /* Setup the counters */ writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC)); @@ -503,6 +502,7 @@ static const u32 sun4i_spi_bits[] = { static const struct sun4i_spi_variant sun4i_a10_spi_variant = { .regs = sun4i_spi_regs, .bits = sun4i_spi_bits, + .fifo_depth = 64, }; static const struct udevice_id sun4i_spi_ids[] = { From 8d71a19edd3fdb687709b240341abc7eebcce77e Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:10 +0530 Subject: [PATCH 07/10] spi: sun4i: Add CLK support Add CLK support to enable AHB and MOD SPI clocks on sun4i_spi driver. Clock disablement could be done while releasing the bus transfer, but the existing code doesn't disable the clocks it only taken care of clock enablement globally in probe. So to make a proper clock handling, the clocks should enable it in claim and disable it in release. This patch would also do that change, by enable and disable clock in proper order. Signed-off-by: Jagan Teki Reviewed-by: Andre Przywara --- drivers/spi/sun4i_spi.c | 56 +++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index 82e69a6b6a..4324d686eb 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -29,8 +30,6 @@ #include #include -#include - #include #define SUN4I_RXDATA_REG 0x00 @@ -140,6 +139,7 @@ struct sun4i_spi_platdata { struct sun4i_spi_priv { struct sun4i_spi_variant *variant; + struct clk clk_ahb, clk_mod; u32 base_addr; u32 freq; u32 mode; @@ -266,13 +266,34 @@ static int sun4i_spi_parse_pins(struct udevice *dev) return 0; } -static inline void sun4i_spi_enable_clock(void) +static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable) { - struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *const)SUNXI_CCM_BASE; + struct sun4i_spi_priv *priv = dev_get_priv(dev); + int ret; - setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0)); - writel((1 << 31), &ccm->spi0_clk_cfg); + if (!enable) { + clk_disable(&priv->clk_ahb); + clk_disable(&priv->clk_mod); + return 0; + } + + ret = clk_enable(&priv->clk_ahb); + if (ret) { + dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret); + return ret; + } + + ret = clk_enable(&priv->clk_mod); + if (ret) { + dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret); + goto err_ahb; + } + + return 0; + +err_ahb: + clk_disable(&priv->clk_ahb); + return ret; } static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) @@ -296,8 +317,20 @@ static int sun4i_spi_probe(struct udevice *bus) { struct sun4i_spi_platdata *plat = dev_get_platdata(bus); struct sun4i_spi_priv *priv = dev_get_priv(bus); + int ret; + + ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb); + if (ret) { + dev_err(dev, "failed to get ahb clock\n"); + return ret; + } + + ret = clk_get_by_name(bus, "mod", &priv->clk_mod); + if (ret) { + dev_err(dev, "failed to get mod clock\n"); + return ret; + } - sun4i_spi_enable_clock(); sun4i_spi_parse_pins(bus); priv->variant = plat->variant; @@ -310,6 +343,11 @@ static int sun4i_spi_probe(struct udevice *bus) static int sun4i_spi_claim_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); + int ret; + + ret = sun4i_spi_set_clock(dev->parent, true); + if (ret) + return ret; setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP)); @@ -326,6 +364,8 @@ static int sun4i_spi_release_bus(struct udevice *dev) clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE); + sun4i_spi_set_clock(dev->parent, false); + return 0; } From 853f4511e99456ad8eae3fadac641bcdb685868d Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:11 +0530 Subject: [PATCH 08/10] spi: sun4: Add A31 spi controller support The usual SPI transmission protocol in Allwinner A10 and A31 controllers share similar context with minimal changes in register offsets along with few additional register bits on A31. So, add A31 spi controller support in existing sun4i_spi with A31 specific register offsets and bits. Signed-off-by: Jagan Teki --- drivers/spi/Kconfig | 4 +- drivers/spi/sun4i_spi.c | 101 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ac7fbab841..15207d23c1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -223,9 +223,9 @@ config STM32_QSPI this ST IP core. config SUN4I_SPI - bool "Allwinner A10 SoCs SPI controller" + bool "Allwinner A10/A31 SoCs SPI controller" help - SPI driver for Allwinner sun4i, sun5i and sun7i SoCs + This enables using the SPI controller on the Allwinner A10/A31 SoCs. config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index 4324d686eb..da9984c004 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,18 @@ #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f #define SUN4I_FIFO_STA_TF_CNT_BITS 16 +/* sun6i spi registers */ +#define SUN6I_GBL_CTL_REG 0x04 +#define SUN6I_TFR_CTL_REG 0x08 +#define SUN6I_FIFO_CTL_REG 0x18 +#define SUN6I_FIFO_STA_REG 0x1c +#define SUN6I_CLK_CTL_REG 0x24 +#define SUN6I_BURST_CNT_REG 0x30 +#define SUN6I_XMIT_CNT_REG 0x34 +#define SUN6I_BURST_CTL_REG 0x38 +#define SUN6I_TXDATA_REG 0x200 +#define SUN6I_RXDATA_REG 0x300 + #define SUN4I_SPI_MAX_RATE 24000000 #define SUN4I_SPI_MIN_RATE 3000 #define SUN4I_SPI_DEFAULT_RATE 1000000 @@ -112,6 +125,7 @@ enum sun4i_spi_regs { /* sun spi register bits */ enum sun4i_spi_bits { SPI_GCR_TP, + SPI_GCR_SRST, SPI_TCR_CPHA, SPI_TCR_CPOL, SPI_TCR_CS_ACTIVE_LOW, @@ -129,6 +143,8 @@ struct sun4i_spi_variant { const unsigned long *regs; const u32 *bits; u32 fifo_depth; + bool has_soft_reset; + bool has_burst_ctl; }; struct sun4i_spi_platdata { @@ -140,6 +156,7 @@ struct sun4i_spi_platdata { struct sun4i_spi_priv { struct sun4i_spi_variant *variant; struct clk clk_ahb, clk_mod; + struct reset_ctl reset; u32 base_addr; u32 freq; u32 mode; @@ -258,7 +275,10 @@ static int sun4i_spi_parse_pins(struct udevice *dev) if (pin < 0) break; - sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); + if (IS_ENABLED(CONFIG_MACH_SUN50I)) + sunxi_gpio_set_cfgpin(pin, SUN50I_GPC_SPI0); + else + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); sunxi_gpio_set_drv(pin, drive); sunxi_gpio_set_pull(pin, pull); } @@ -274,6 +294,8 @@ static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable) if (!enable) { clk_disable(&priv->clk_ahb); clk_disable(&priv->clk_mod); + if (reset_valid(&priv->reset)) + reset_assert(&priv->reset); return 0; } @@ -289,8 +311,18 @@ static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable) goto err_ahb; } + if (reset_valid(&priv->reset)) { + ret = reset_deassert(&priv->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + goto err_mod; + } + } + return 0; +err_mod: + clk_disable(&priv->clk_mod); err_ahb: clk_disable(&priv->clk_ahb); return ret; @@ -331,6 +363,12 @@ static int sun4i_spi_probe(struct udevice *bus) return ret; } + ret = reset_get_by_index(bus, 0, &priv->reset); + if (ret && ret != -ENOENT) { + dev_err(dev, "failed to get reset\n"); + return ret; + } + sun4i_spi_parse_pins(bus); priv->variant = plat->variant; @@ -352,6 +390,10 @@ static int sun4i_spi_claim_bus(struct udevice *dev) setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP)); + if (priv->variant->has_soft_reset) + setbits_le32(SPI_REG(priv, SPI_GCR), + SPI_BIT(priv, SPI_GCR_SRST)); + setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) | SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW)); @@ -404,6 +446,10 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC)); writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC)); + if (priv->variant->has_burst_ctl) + writel(SUN4I_BURST_CNT(nbytes), + SPI_REG(priv, SPI_BCTL)); + /* Fill the TX FIFO */ sun4i_spi_fill_fifo(priv, nbytes); @@ -539,17 +585,70 @@ static const u32 sun4i_spi_bits[] = { [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0), }; +static const unsigned long sun6i_spi_regs[] = { + [SPI_GCR] = SUN6I_GBL_CTL_REG, + [SPI_TCR] = SUN6I_TFR_CTL_REG, + [SPI_FCR] = SUN6I_FIFO_CTL_REG, + [SPI_FSR] = SUN6I_FIFO_STA_REG, + [SPI_CCR] = SUN6I_CLK_CTL_REG, + [SPI_BC] = SUN6I_BURST_CNT_REG, + [SPI_TC] = SUN6I_XMIT_CNT_REG, + [SPI_BCTL] = SUN6I_BURST_CTL_REG, + [SPI_TXD] = SUN6I_TXDATA_REG, + [SPI_RXD] = SUN6I_RXDATA_REG, +}; + +static const u32 sun6i_spi_bits[] = { + [SPI_GCR_TP] = BIT(7), + [SPI_GCR_SRST] = BIT(31), + [SPI_TCR_CPHA] = BIT(0), + [SPI_TCR_CPOL] = BIT(1), + [SPI_TCR_CS_ACTIVE_LOW] = BIT(2), + [SPI_TCR_CS_SEL] = 4, + [SPI_TCR_CS_MASK] = 0x30, + [SPI_TCR_CS_MANUAL] = BIT(6), + [SPI_TCR_CS_LEVEL] = BIT(7), + [SPI_TCR_XCH] = BIT(31), + [SPI_FCR_RF_RST] = BIT(15), + [SPI_FCR_TF_RST] = BIT(31), + [SPI_FSR_RF_CNT_MASK] = GENMASK(7, 0), +}; + static const struct sun4i_spi_variant sun4i_a10_spi_variant = { .regs = sun4i_spi_regs, .bits = sun4i_spi_bits, .fifo_depth = 64, }; +static const struct sun4i_spi_variant sun6i_a31_spi_variant = { + .regs = sun6i_spi_regs, + .bits = sun6i_spi_bits, + .fifo_depth = 128, + .has_soft_reset = true, + .has_burst_ctl = true, +}; + +static const struct sun4i_spi_variant sun8i_h3_spi_variant = { + .regs = sun6i_spi_regs, + .bits = sun6i_spi_bits, + .fifo_depth = 64, + .has_soft_reset = true, + .has_burst_ctl = true, +}; + static const struct udevice_id sun4i_spi_ids[] = { { .compatible = "allwinner,sun4i-a10-spi", .data = (ulong)&sun4i_a10_spi_variant, }, + { + .compatible = "allwinner,sun6i-a31-spi", + .data = (ulong)&sun6i_a31_spi_variant, + }, + { + .compatible = "allwinner,sun8i-h3-spi", + .data = (ulong)&sun8i_h3_spi_variant, + }, { } }; From 903e7cf37ceb0552f6b8948e30fb9bb662980cd9 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:12 +0530 Subject: [PATCH 09/10] spi: sun4i: Driver cleanup - drop unused macros. - use base instead of base_addr, for better code readability - move .probe and .ofdata_to_platdata functions in required places to add platdata support in future. - use sentinel sun4i_spi_ids. Signed-off-by: Jagan Teki --- drivers/spi/sun4i_spi.c | 190 +++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 110 deletions(-) diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index da9984c004..dbfeac77ee 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -33,57 +33,16 @@ #include -#define SUN4I_RXDATA_REG 0x00 +DECLARE_GLOBAL_DATA_PTR; -#define SUN4I_TXDATA_REG 0x04 - -#define SUN4I_CTL_REG 0x08 -#define SUN4I_CTL_ENABLE BIT(0) -#define SUN4I_CTL_MASTER BIT(1) -#define SUN4I_CTL_CPHA BIT(2) -#define SUN4I_CTL_CPOL BIT(3) -#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4) -#define SUN4I_CTL_LMTF BIT(6) -#define SUN4I_CTL_TF_RST BIT(8) -#define SUN4I_CTL_RF_RST BIT(9) -#define SUN4I_CTL_XCH BIT(10) -#define SUN4I_CTL_CS_MASK 0x3000 -#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK) -#define SUN4I_CTL_DHB BIT(15) -#define SUN4I_CTL_CS_MANUAL BIT(16) -#define SUN4I_CTL_CS_LEVEL BIT(17) -#define SUN4I_CTL_TP BIT(18) - -#define SUN4I_INT_CTL_REG 0x0c -#define SUN4I_INT_CTL_RF_F34 BIT(4) -#define SUN4I_INT_CTL_TF_E34 BIT(12) -#define SUN4I_INT_CTL_TC BIT(16) - -#define SUN4I_INT_STA_REG 0x10 - -#define SUN4I_DMA_CTL_REG 0x14 - -#define SUN4I_WAIT_REG 0x18 - -#define SUN4I_CLK_CTL_REG 0x1c -#define SUN4I_CLK_CTL_CDR2_MASK 0xff -#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK) -#define SUN4I_CLK_CTL_CDR1_MASK 0xf -#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) -#define SUN4I_CLK_CTL_DRS BIT(12) - -#define SUN4I_MAX_XFER_SIZE 0xffffff - -#define SUN4I_BURST_CNT_REG 0x20 -#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) - -#define SUN4I_XMIT_CNT_REG 0x24 -#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) - -#define SUN4I_FIFO_STA_REG 0x28 -#define SUN4I_FIFO_STA_RF_CNT_BITS 0 -#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f -#define SUN4I_FIFO_STA_TF_CNT_BITS 16 +/* sun4i spi registers */ +#define SUN4I_RXDATA_REG 0x00 +#define SUN4I_TXDATA_REG 0x04 +#define SUN4I_CTL_REG 0x08 +#define SUN4I_CLK_CTL_REG 0x1c +#define SUN4I_BURST_CNT_REG 0x20 +#define SUN4I_XMIT_CNT_REG 0x24 +#define SUN4I_FIFO_STA_REG 0x28 /* sun6i spi registers */ #define SUN6I_GBL_CTL_REG 0x04 @@ -97,12 +56,25 @@ #define SUN6I_TXDATA_REG 0x200 #define SUN6I_RXDATA_REG 0x300 -#define SUN4I_SPI_MAX_RATE 24000000 -#define SUN4I_SPI_MIN_RATE 3000 -#define SUN4I_SPI_DEFAULT_RATE 1000000 -#define SUN4I_SPI_TIMEOUT_US 1000000 +/* sun spi bits */ +#define SUN4I_CTL_ENABLE BIT(0) +#define SUN4I_CTL_MASTER BIT(1) +#define SUN4I_CLK_CTL_CDR2_MASK 0xff +#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK) +#define SUN4I_CLK_CTL_CDR1_MASK 0xf +#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) +#define SUN4I_CLK_CTL_DRS BIT(12) +#define SUN4I_MAX_XFER_SIZE 0xffffff +#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) +#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) +#define SUN4I_FIFO_STA_RF_CNT_BITS 0 -#define SPI_REG(priv, reg) ((priv)->base_addr + \ +#define SUN4I_SPI_MAX_RATE 24000000 +#define SUN4I_SPI_MIN_RATE 3000 +#define SUN4I_SPI_DEFAULT_RATE 1000000 +#define SUN4I_SPI_TIMEOUT_US 1000000 + +#define SPI_REG(priv, reg) ((priv)->base + \ (priv)->variant->regs[reg]) #define SPI_BIT(priv, bit) ((priv)->variant->bits[bit]) #define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \ @@ -149,7 +121,7 @@ struct sun4i_spi_variant { struct sun4i_spi_platdata { struct sun4i_spi_variant *variant; - u32 base_addr; + u32 base; u32 max_hz; }; @@ -157,7 +129,7 @@ struct sun4i_spi_priv { struct sun4i_spi_variant *variant; struct clk clk_ahb, clk_mod; struct reset_ctl reset; - u32 base_addr; + u32 base; u32 freq; u32 mode; @@ -165,8 +137,6 @@ struct sun4i_spi_priv { u8 *rx_buf; }; -DECLARE_GLOBAL_DATA_PTR; - static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len) { u8 byte; @@ -328,56 +298,6 @@ err_ahb: return ret; } -static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) -{ - struct sun4i_spi_platdata *plat = dev_get_platdata(bus); - int node = dev_of_offset(bus); - - plat->base_addr = devfdt_get_addr(bus); - plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus); - plat->max_hz = fdtdec_get_int(gd->fdt_blob, node, - "spi-max-frequency", - SUN4I_SPI_DEFAULT_RATE); - - if (plat->max_hz > SUN4I_SPI_MAX_RATE) - plat->max_hz = SUN4I_SPI_MAX_RATE; - - return 0; -} - -static int sun4i_spi_probe(struct udevice *bus) -{ - struct sun4i_spi_platdata *plat = dev_get_platdata(bus); - struct sun4i_spi_priv *priv = dev_get_priv(bus); - int ret; - - ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb); - if (ret) { - dev_err(dev, "failed to get ahb clock\n"); - return ret; - } - - ret = clk_get_by_name(bus, "mod", &priv->clk_mod); - if (ret) { - dev_err(dev, "failed to get mod clock\n"); - return ret; - } - - ret = reset_get_by_index(bus, 0, &priv->reset); - if (ret && ret != -ENOENT) { - dev_err(dev, "failed to get reset\n"); - return ret; - } - - sun4i_spi_parse_pins(bus); - - priv->variant = plat->variant; - priv->base_addr = plat->base_addr; - priv->freq = plat->max_hz; - - return 0; -} - static int sun4i_spi_claim_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); @@ -558,6 +478,56 @@ static const struct dm_spi_ops sun4i_spi_ops = { .set_mode = sun4i_spi_set_mode, }; +static int sun4i_spi_probe(struct udevice *bus) +{ + struct sun4i_spi_platdata *plat = dev_get_platdata(bus); + struct sun4i_spi_priv *priv = dev_get_priv(bus); + int ret; + + ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb); + if (ret) { + dev_err(dev, "failed to get ahb clock\n"); + return ret; + } + + ret = clk_get_by_name(bus, "mod", &priv->clk_mod); + if (ret) { + dev_err(dev, "failed to get mod clock\n"); + return ret; + } + + ret = reset_get_by_index(bus, 0, &priv->reset); + if (ret && ret != -ENOENT) { + dev_err(dev, "failed to get reset\n"); + return ret; + } + + sun4i_spi_parse_pins(bus); + + priv->variant = plat->variant; + priv->base = plat->base; + priv->freq = plat->max_hz; + + return 0; +} + +static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct sun4i_spi_platdata *plat = dev_get_platdata(bus); + int node = dev_of_offset(bus); + + plat->base = devfdt_get_addr(bus); + plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus); + plat->max_hz = fdtdec_get_int(gd->fdt_blob, node, + "spi-max-frequency", + SUN4I_SPI_DEFAULT_RATE); + + if (plat->max_hz > SUN4I_SPI_MAX_RATE) + plat->max_hz = SUN4I_SPI_MAX_RATE; + + return 0; +} + static const unsigned long sun4i_spi_regs[] = { [SPI_GCR] = SUN4I_CTL_REG, [SPI_TCR] = SUN4I_CTL_REG, @@ -649,7 +619,7 @@ static const struct udevice_id sun4i_spi_ids[] = { .compatible = "allwinner,sun8i-h3-spi", .data = (ulong)&sun8i_h3_spi_variant, }, - { } + { /* sentinel */ } }; U_BOOT_DRIVER(sun4i_spi) = { From a51cd54eff284ee42bfc1b74b8581daec78496f6 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 27 Feb 2019 20:02:13 +0530 Subject: [PATCH 10/10] spi: Rename sun4i_spi.c into spi-sunxi.c Now the same SPI controller driver is reusable in all Allwinner SoC variants, so rename the existing sun4i_spi.c into spi-sunxi.c which eventually look like a common sunxi driver. Also update the function, variable, structure names in driver from sun4i into sunxi. Signed-off-by: Jagan Teki --- drivers/spi/Kconfig | 12 +++++++----- drivers/spi/Makefile | 2 +- drivers/spi/{sun4i_spi.c => spi-sunxi.c} | 0 3 files changed, 8 insertions(+), 6 deletions(-) rename drivers/spi/{sun4i_spi.c => spi-sunxi.c} (100%) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 15207d23c1..098372e093 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -213,6 +213,13 @@ config SANDBOX_SPI }; }; +config SPI_SUNXI + bool "Allwinner SoC SPI controllers" + help + Enable the Allwinner SoC SPi controller driver. + + Same controller driver can reuse in all Allwinner SoC variants. + config STM32_QSPI bool "STM32F7 QSPI driver" depends on STM32F7 @@ -222,11 +229,6 @@ config STM32_QSPI used to access the SPI NOR flash chips on platforms embedding this ST IP core. -config SUN4I_SPI - bool "Allwinner A10/A31 SoCs SPI controller" - help - This enables using the SPI controller on the Allwinner A10/A31 SoCs. - config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3902671293..01907bef79 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -48,10 +48,10 @@ obj-$(CONFIG_PL022_SPI) += pl022_spi.o obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o +obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o obj-$(CONFIG_SH_SPI) += sh_spi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o -obj-$(CONFIG_SUN4I_SPI) += sun4i_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/spi-sunxi.c similarity index 100% rename from drivers/spi/sun4i_spi.c rename to drivers/spi/spi-sunxi.c