mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
| --- 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 <linux/gpio.h>
 | |
|  #include <linux/of_gpio.h>
 | |
|  #include <linux/pinctrl/consumer.h>
 | |
| +#include <linux/of_address.h>
 | |
|  
 | |
|  /*
 | |
|   * 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,
 |