--- linux-4.9.37/drivers/spi/spi-pl022.c 2017-07-12 16:42:41.000000000 +0300 +++ linux-4.9.y/drivers/spi/spi-pl022.c 2021-06-07 13:01:34.000000000 +0300 @@ -43,6 +43,7 @@ #include #include #include +#include /* * This macro is used to define some register default values. @@ -136,6 +137,18 @@ /* This one is only in the PL023 variant */ #define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13) +#ifdef CONFIG_ARCH_GOKE +/* + * The Goke version of this block adds some bits + * in SSP_CR1 + */ +#define SSP_CR1_MASK_BIGEND_GOKE (0x1UL << 4) +#define SSP_CR1_MASK_ALTASENS_GOKE (0x1UL << 6) + +#define SSP_TX_FIFO_CR(r) (r + 0x28) +#define SSP_RX_FIFO_CR(r) (r + 0x2C) +#endif + /* * SSP Status Register - SSP_SR */ @@ -296,6 +309,10 @@ #define SPI_POLLING_TIMEOUT 1000 +#ifdef CONFIG_ARCH_GOKE +#define PL022_IDS_INDEX_GOKE 4 +#endif + /* * The type of reading going on on this chip */ @@ -337,6 +354,15 @@ bool internal_cs_ctrl; }; +#ifdef CONFIG_ARCH_GOKE +struct cs_data { + struct resource res; + void __iomem *virt_addr; + unsigned int cs_sb; + unsigned int cs_mask_bit; +}; +#endif + /** * struct pl022 - This is the private SSP driver data structure * @adev: AMBA device model hookup @@ -346,6 +372,13 @@ * @clk: outgoing clock "SPICLK" for the SPI bus * @master: SPI framework hookup * @master_info: controller-specific data from machine setup + * @kworker: thread struct for message pump + * @kworker_task: pointer to task for message pump kworker thread + * @pump_messages: work struct for scheduling work to the message pump + * @queue_lock: spinlock to syncronise access to message queue + * @queue: message queue + * @busy: message pump is busy + * @running: message pump is running * @pump_transfers: Tasklet used in Interrupt Transfer mode * @cur_msg: Pointer to current spi_message being processed * @cur_transfer: Pointer to current spi_transfer @@ -403,6 +436,9 @@ #endif int cur_cs; int *chipselects; +#ifdef CONFIG_ARCH_GOKE + struct cs_data *cs_data; +#endif }; /** @@ -459,13 +495,41 @@ static void internal_cs_control(struct pl022 *pl022, u32 command) { u32 tmp; - +#ifdef CONFIG_ARCH_GOKE + struct amba_device *adev = pl022->adev; + struct amba_driver *adrv = container_of(adev->dev.driver, + struct amba_driver, drv); + + if (pl022->vendor->extended_cr && (adev->periphid == + adrv->id_table[PL022_IDS_INDEX_GOKE].id)) { + if (pl022->cs_data) { + tmp = readl(pl022->cs_data->virt_addr); + tmp &= ~(pl022->cs_data->cs_mask_bit); + tmp |= ((u32)pl022->cur_cs) << pl022->cs_data->cs_sb; + writel(tmp, pl022->cs_data->virt_addr); + } + + if (command == SSP_CHIP_SELECT) + /* Enable SSP */ + writew((readw(SSP_CR1(pl022->virtbase)) | + SSP_CR1_MASK_SSE), + SSP_CR1(pl022->virtbase)); + else + /* disable SSP */ + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), + SSP_CR1(pl022->virtbase)); + } else { +#endif tmp = readw(SSP_CSR(pl022->virtbase)); if (command == SSP_CHIP_SELECT) - tmp &= ~BIT(pl022->cur_cs); + tmp &= ~BIT((u32)pl022->cur_cs); else - tmp |= BIT(pl022->cur_cs); + tmp |= BIT((u32)pl022->cur_cs); writew(tmp, SSP_CSR(pl022->virtbase)); +#ifdef CONFIG_ARCH_GOKE + } +#endif } static void pl022_cs_control(struct pl022 *pl022, u32 command) @@ -566,8 +630,16 @@ static void restore_state(struct pl022 *pl022) { struct chip_data *chip = pl022->cur_chip; +#ifdef CONFIG_ARCH_GOKE + struct amba_device *adev = pl022->adev; + struct amba_driver *adrv = container_of(adev->dev.driver, + struct amba_driver, drv); + if (pl022->vendor->extended_cr && (adev->periphid != + adrv->id_table[PL022_IDS_INDEX_GOKE].id)) +#else if (pl022->vendor->extended_cr) +#endif writel(chip->cr0, SSP_CR0(pl022->virtbase)); else writew(chip->cr0, SSP_CR0(pl022->virtbase)); @@ -640,6 +712,15 @@ GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \ ) +#ifdef CONFIG_ARCH_GOKE +/* Goke versions extend this register to use all 16 bits */ +#define DEFAULT_SSP_REG_CR1_GOKE ( \ + DEFAULT_SSP_REG_CR1 | \ + GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_BIGEND_GOKE, 4) | \ + GEN_MASK_BITS(0x0, SSP_CR1_MASK_ALTASENS_GOKE, 6) \ +) +#endif + #define DEFAULT_SSP_REG_CPSR ( \ GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \ ) @@ -659,8 +740,22 @@ writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase)); writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase)); } else if (pl022->vendor->extended_cr) { +#ifdef CONFIG_ARCH_GOKE + struct amba_device *adev = pl022->adev; + struct amba_driver *adrv = container_of(adev->dev.driver, + struct amba_driver, drv); + + if (adev->periphid == adrv->id_table[PL022_IDS_INDEX_GOKE].id) { + writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); + writew(DEFAULT_SSP_REG_CR1_GOKE, + SSP_CR1(pl022->virtbase)); + } else { +#endif writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase)); writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase)); +#ifdef CONFIG_ARCH_GOKE + } +#endif } else { writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase)); @@ -1803,7 +1898,7 @@ .com_mode = POLLING_TRANSFER, .iface = SSP_INTERFACE_MOTOROLA_SPI, .hierarchy = SSP_SLAVE, - .slave_tx_disable = DO_NOT_DRIVE_TX, + .slave_tx_disable = DRIVE_TX, .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, .ctrl_len = SSP_BITS_8, @@ -1835,6 +1930,13 @@ unsigned int bits = spi->bits_per_word; u32 tmp; struct device_node *np = spi->dev.of_node; +#ifdef CONFIG_ARCH_GOKE + struct amba_device *adev = pl022->adev; + struct amba_driver *adrv = container_of(adev->dev.driver, + struct amba_driver, drv); + writel(0, SSP_TX_FIFO_CR(pl022->virtbase)); + writel(0, SSP_RX_FIFO_CR(pl022->virtbase)); +#endif if (!spi->max_speed_hz) return -EINVAL; @@ -1856,8 +1958,10 @@ if (chip_info == NULL) { if (np) { chip_info_dt = pl022_default_chip_info; - - chip_info_dt.hierarchy = SSP_MASTER; + if(pl022->master->slave) + chip_info_dt.hierarchy = SSP_SLAVE; + else + chip_info_dt.hierarchy = SSP_MASTER; of_property_read_u32(np, "pl022,interface", &chip_info_dt.iface); of_property_read_u32(np, "pl022,com-mode", @@ -1977,7 +2081,12 @@ chip->cpsr = clk_freq.cpsdvsr; /* Special setup for the ST micro extended control registers */ +#ifdef CONFIG_ARCH_GOKE + if (pl022->vendor->extended_cr && (adev->periphid != + adrv->id_table[PL022_IDS_INDEX_GOKE].id)) { +#else if (pl022->vendor->extended_cr) { +#endif u32 etx; if (pl022->vendor->pl023) { @@ -2011,6 +2120,22 @@ SSP_CR1_MASK_RXIFLSEL_ST, 7); SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL_ST, 10); +#ifdef CONFIG_ARCH_GOKE + } else if (pl022->vendor->extended_cr && (adev->periphid == + adrv->id_table[PL022_IDS_INDEX_GOKE].id)) { + SSP_WRITE_BITS(chip->cr0, bits - 1, + SSP_CR0_MASK_DSS, 0); + SSP_WRITE_BITS(chip->cr0, chip_info->iface, + SSP_CR0_MASK_FRF, 4); + + if (spi->mode & SPI_LSB_FIRST) + tmp = !!SPI_LSB_FIRST; + else + tmp = !SPI_LSB_FIRST; + + SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_BIGEND_GOKE, 4); + SSP_WRITE_BITS(chip->cr1, 0x0, SSP_CR1_MASK_ALTASENS_GOKE, 6); +#endif } else { SSP_WRITE_BITS(chip->cr0, bits - 1, SSP_CR0_MASK_DSS, 0); @@ -2099,11 +2224,14 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; + struct amba_driver *adrv = container_of(adev->dev.driver, + struct amba_driver, drv); struct pl022_ssp_controller *platform_info = dev_get_platdata(&adev->dev); struct spi_master *master; struct pl022 *pl022 = NULL; /*Data for this driver */ struct device_node *np = adev->dev.of_node; + unsigned int slave_mode; int status = 0, i, num_cs; dev_info(&adev->dev, @@ -2156,12 +2284,62 @@ master->rt = platform_info->rt; master->dev.of_node = dev->of_node; + if (of_property_read_u32(np, "pl022,slave_mode", + &slave_mode) == 0) { + if (slave_mode == 1){ + master->slave = true; + } else if (slave_mode == 0) { + master->slave = false; + } else { + dev_err(&adev->dev, "spi Master/Slave mode err!!!\n"); + goto err_no_gpio; + } + + } + if (platform_info->num_chipselect && platform_info->chipselects) { for (i = 0; i < num_cs; i++) pl022->chipselects[i] = platform_info->chipselects[i]; } else if (pl022->vendor->internal_cs_ctrl) { for (i = 0; i < num_cs; i++) pl022->chipselects[i] = i; + +#ifdef CONFIG_ARCH_GOKE + if ((adev->periphid == adrv->id_table[PL022_IDS_INDEX_GOKE].id) + && pl022->vendor->extended_cr + && (num_cs > 1)) { + pl022->cs_data = devm_kzalloc(dev, + sizeof(struct cs_data), + GFP_KERNEL); + if (!pl022->cs_data) { + status = -ENOMEM; + goto err_no_mem; + } + + if (of_address_to_resource(np, 1, + &pl022->cs_data->res)) { + status = -EPROBE_DEFER; + goto err_no_gpio; + } + + if (of_property_read_u32(np, "spi_cs_sb", + &pl022->cs_data->cs_sb)) { + status = -EPROBE_DEFER; + goto err_no_gpio; + } + + if (of_property_read_u32(np, "spi_cs_mask_bit", + &pl022->cs_data->cs_mask_bit)) { + status = -EPROBE_DEFER; + goto err_no_gpio; + } + + pl022->cs_data->virt_addr = devm_ioremap(dev, + pl022->cs_data->res.start, + resource_size(&adev->res)); + } else + pl022->cs_data = NULL; +#endif } else if (IS_ENABLED(CONFIG_OF)) { for (i = 0; i < num_cs; i++) { int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); @@ -2288,6 +2466,11 @@ err_no_ioremap: amba_release_regions(adev); err_no_ioregion: +#ifdef CONFIG_ARCH_GOKE + if (pl022->cs_data) + release_mem_region(pl022->cs_data->res.start, + resource_size(&pl022->cs_data->res)); +#endif err_no_gpio: err_no_mem: spi_master_put(master); @@ -2314,6 +2497,11 @@ clk_disable_unprepare(pl022->clk); amba_release_regions(adev); +#ifdef CONFIG_ARCH_GOKE + if (pl022->cs_data) + release_mem_region(pl022->cs_data->res.start, + resource_size(&pl022->cs_data->res)); +#endif tasklet_disable(&pl022->pump_transfers); return 0; } @@ -2390,13 +2578,13 @@ }; static struct vendor_data vendor_arm = { - .fifodepth = 8, + .fifodepth = 256, .max_bpw = 16, .unidir = false, - .extended_cr = false, + .extended_cr = true, .pl023 = false, .loopback = true, - .internal_cs_ctrl = false, + .internal_cs_ctrl = true, }; static struct vendor_data vendor_st = { @@ -2433,7 +2621,7 @@ { /* * ARM PL022 variant, this has a 16bit wide - * and 8 locations deep TX/RX FIFO + * and 256 locations deep TX/RX FIFO */ .id = 0x00041022, .mask = 0x000fffff,