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,
|