diff --git a/arch/arm/configs/nanopi2_linux_defconfig b/arch/arm/configs/nanopi2_linux_defconfig index e70570ed899..87fe7f0555d 100644 --- a/arch/arm/configs/nanopi2_linux_defconfig +++ b/arch/arm/configs/nanopi2_linux_defconfig @@ -1583,8 +1583,8 @@ CONFIG_SPI_PL022_PORT0=y CONFIG_USE_DMA_PORT0=y # CONFIG_SPI_PL022_PORT1 is not set # CONFIG_USE_DMA_PORT1 is not set -# CONFIG_SPI_PL022_PORT2 is not set -# CONFIG_USE_DMA_PORT2 is not set +CONFIG_SPI_PL022_PORT2=y +CONFIG_USE_DMA_PORT2=y # CONFIG_SPI_PXA2XX_PCI is not set # CONFIG_SPI_XILINX is not set # CONFIG_SPI_DESIGNWARE is not set diff --git a/arch/arm/plat-s5p4418/nanopi2/device.c b/arch/arm/plat-s5p4418/nanopi2/device.c index 7875ba8c09c..f2da4d501ac 100644 --- a/arch/arm/plat-s5p4418/nanopi2/device.c +++ b/arch/arm/plat-s5p4418/nanopi2/device.c @@ -1467,6 +1467,51 @@ static struct spi_board_info spi_plat_board[] __initdata = { }; #endif +#define CFG_SPI2_CS (PAD_GPIO_C + 10) + +static void mylcd_cs(u32 chipselect) +{ + +#if (CFG_SPI2_CS_GPIO_MODE) + nxp_soc_gpio_set_out_value( CFG_SPI2_CS , chipselect); +#else + ; +#endif +} + +struct pl022_config_chip mylcd_info = { + /* available POLLING_TRANSFER, INTERRUPT_TRANSFER, DMA_TRANSFER */ + .com_mode = CFG_SPI2_COM_MODE, + .iface = SSP_INTERFACE_MOTOROLA_SPI, + /* We can only act as master but SSP_SLAVE is possible in theory */ + .hierarchy = SSP_MASTER, + /* 0 = drive TX even as slave, 1 = do not drive TX as slave */ + .slave_tx_disable = 1, + .rx_lev_trig = SSP_RX_4_OR_MORE_ELEM, + .tx_lev_trig = SSP_TX_4_OR_MORE_EMPTY_LOC, + .ctrl_len = SSP_BITS_8, + .wait_state = SSP_MWIRE_WAIT_ZERO, + .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, + /* + * This is where you insert a call to a function to enable CS + * (usually GPIO) for a certain chip. + */ + .cs_control = mylcd_cs, + .clkdelay = SSP_FEEDBACK_CLK_DELAY_1T, +}; + +static struct spi_board_info spi2_plat_board[] __initdata = { + [0] = { + .modalias = "my_spilcd", /* fixup */ + .max_speed_hz = 50000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 2, /* Note> set bus num, must be smaller than ARRAY_SIZE(spi_plat_device) */ + .chip_select = 0, /* Note> set chip select num, must be smaller than spi cs_num */ + .controller_data = &mylcd_info, + .mode = SPI_MODE_0, + }, +}; + + /*------------------------------------------------------------------------------ * DW MMC board config */ @@ -1943,6 +1988,19 @@ void __init nxp_board_devices_register(void) printk("plat: register spidev\n"); #endif + nxp_soc_gpio_set_io_func(PAD_GPIO_C + 9, NX_GPIO_PADFUNC_2); +#if (CFG_SPI2_CS_GPIO_MODE) + nxp_soc_gpio_set_io_func(PAD_GPIO_C + 10, NX_GPIO_PADFUNC_1); + nxp_soc_gpio_set_io_dir( CFG_SPI2_CS, 1); +#else + nxp_soc_gpio_set_io_func(PAD_GPIO_C + 10, NX_GPIO_PADFUNC_2); +#endif + nxp_soc_gpio_set_io_func(PAD_GPIO_C + 11, NX_GPIO_PADFUNC_2); + nxp_soc_gpio_set_io_func(PAD_GPIO_C + 12, NX_GPIO_PADFUNC_2); + spi_register_board_info(spi2_plat_board, ARRAY_SIZE(spi2_plat_board)); + printk("plat: register mylcd\n"); + + #if defined(CONFIG_TOUCHSCREEN_GSLX680) printk("plat: add touch(gslX680) device\n"); i2c_register_board_info(GSLX680_I2C_BUS, &gslX680_i2c_bdi, 1); diff --git a/arch/arm/plat-s5p4418/nanopi2/include/cfg_main.h b/arch/arm/plat-s5p4418/nanopi2/include/cfg_main.h index dce2f0af004..da28f18d99c 100644 --- a/arch/arm/plat-s5p4418/nanopi2/include/cfg_main.h +++ b/arch/arm/plat-s5p4418/nanopi2/include/cfg_main.h @@ -200,19 +200,20 @@ /*------------------------------------------------------------------------------ * SPI */ -#define CFG_SPI0_CLK (10000000*5) // spiclk = CFG_SPI0_CLK / 2 -#define CFG_SPI1_CLK 10000000 -#define CFG_SPI2_CLK 10000000 +#define CFG_SPI0_CLK (10000000*10) // spiclk = CFG_SPI0_CLK / 2 +#define CFG_SPI1_CLK (10000000*10) +#define CFG_SPI2_CLK (10000000*10) -#define CFG_SPI0_COM_MODE 0 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ -#define CFG_SPI1_COM_MODE 1 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ -#define CFG_SPI2_COM_MODE 1 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ +#define CFG_SPI0_COM_MODE 2 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ +#define CFG_SPI1_COM_MODE 2 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ +#define CFG_SPI2_COM_MODE 2 /* available 0: INTERRUPT_TRANSFER, 1: POLLING_TRANSFER, 2: DMA_TRANSFER */ #define CFG_SPI0_CS_GPIO_MODE 1 /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ #define CFG_SPI1_CS_GPIO_MODE 1 /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ -#define CFG_SPI2_CS_GPIO_MODE 0 /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ +#define CFG_SPI2_CS_GPIO_MODE 1 /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ #define CFG_SPI0_CS (PAD_GPIO_C + 30) /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ +#define CFG_SPI2_CS (PAD_GPIO_C + 10) /* 0 FSS CONTROL, 1: CS CONTRO GPIO MODE */ /*------------------------------------------------------------------------------ * MPEGTSIF diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 767c4b29ed4..e577aa737f4 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -117,6 +117,12 @@ struct pl08x_lli { u32 cctl; }; +struct ssp_monitor { + int index; + struct timer_list timer; + spinlock_t ssp_lock; +}; + /** * struct pl08x_driver_data - the local state holder for the PL08x * @slave: slave engine for this instance @@ -146,6 +152,7 @@ struct pl08x_driver_data { u8 lli_buses; u8 mem_buses; spinlock_t lock; + struct ssp_monitor ssp_monitor[3]; }; /* @@ -2099,10 +2106,57 @@ static void pl08x_tasklet(unsigned long data) } } + +static void pl08x_ssp_timer(unsigned long data) +{ + struct ssp_monitor *monitor = (struct ssp_monitor *)data; + struct pl08x_driver_data *pl08x = container_of(monitor, + struct pl08x_driver_data, ssp_monitor[monitor->index]); + unsigned long flags, ch_id, val; + struct pl08x_phy_chan *phychan = &pl08x->phy_chans[0]; + int i, num_req; + + ch_id = DMA_PERIPHERAL_ID_SSP0_RX + 2 * monitor->index; + + spin_lock_irqsave(&monitor->ssp_lock, flags); + for(i = 0; i < pl08x->vd->channels; i++) { + if(phychan->serving->cd->min_signal == ch_id) + break; + phychan++; + } + num_req = readl(phychan->base + PL080_CH_CONTROL) & 0xFFF; + val = 1 << ch_id; + for(i = 0; i < DIV_ROUND_UP(num_req, 4); i++) + writel(val, pl08x->base + PL080_SOFT_BREQ); + spin_unlock_irqrestore(&monitor->ssp_lock, flags); +} + +void prevent_abnormal_ssp_task(struct pl08x_driver_data *pl08x, u16 ssp_tc) +{ + int i = 0; + + for(i = 0; i < 3; i++) { + int bit = DMA_PERIPHERAL_ID_SSP0_TX + 2 * i; + int spi_tx = 0, spi_rx = 0; + + spi_tx = ssp_tc & (1 << bit); + spi_rx = ssp_tc & (1 << (bit + 1)); + + if(spi_tx && !spi_rx) { + mod_timer(&pl08x->ssp_monitor[i].timer,jiffies + msecs_to_jiffies(8)); + } + + if(!spi_tx && spi_rx) { + del_timer(&pl08x->ssp_monitor[i].timer); + } + } +} + static irqreturn_t pl08x_irq(int irq, void *dev) { struct pl08x_driver_data *pl08x = dev; u32 mask = 0, err, tc, i; + u16 ssp_tc_record_bit = 0; /* check & clear - ERR & TC interrupts */ err = readl(pl08x->base + PL080_ERR_STATUS); @@ -2131,6 +2185,11 @@ static irqreturn_t pl08x_irq(int irq, void *dev) continue; } + /* Only DMAC0 contains SPI. */ + if(pl08x->slave.chancnt == 16){ + ssp_tc_record_bit |= (1 << plchan->cd->min_signal); + } + /* Schedule tasklet on this channel */ #if !defined(CONFIG_AMBA_PL08X_USE_ISR) tasklet_schedule(&plchan->tasklet); @@ -2140,6 +2199,8 @@ static irqreturn_t pl08x_irq(int irq, void *dev) mask |= (1 << i); } } + if(ssp_tc_record_bit) + prevent_abnormal_ssp_task(pl08x, ssp_tc_record_bit); return mask ? IRQ_HANDLED : IRQ_NONE; } @@ -2388,6 +2449,13 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_set_active(&adev->dev); pm_runtime_enable(&adev->dev); + for(i = 0; i < 3; i++){ + pl08x->ssp_monitor[i].index = i; + spin_lock_init(&pl08x->ssp_monitor[i].ssp_lock); + setup_timer(&pl08x->ssp_monitor[i].timer, + pl08x_ssp_timer, (unsigned long)&pl08x->ssp_monitor[i]); + } + /* Initialize memcpy engine */ dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); pl08x->memcpy.dev = &adev->dev; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index c05b20a6d3c..3014e017d88 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1408,8 +1408,9 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022) } /* If we're using DMA, set up DMA here */ - if (pl022->cur_chip->enable_dma && !(pl022->cur_transfer->len % 4) && (pl022->cur_transfer->len < 4096)) { //bok add +// if (pl022->cur_chip->enable_dma && !(pl022->cur_transfer->len % 4) && (pl022->cur_transfer->len < 4096)) { //bok add // if (pl022->cur_chip->enable_dma) { + if (pl022->cur_chip->enable_dma && !(pl022->cur_transfer->len % 4)) { /* Configure DMA transfer */ if (configure_dma(pl022)) { dev_dbg(&pl022->adev->dev,