--- zzzz-none-000/linux-3.10.107/drivers/spi/spi-mpc512x-psc.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/spi/spi-mpc512x-psc.c 2021-02-04 17:41:59.000000000 +0000 @@ -16,12 +16,11 @@ #include #include -#include #include #include #include +#include #include -#include #include #include #include @@ -31,26 +30,45 @@ #include #include +enum { + TYPE_MPC5121, + TYPE_MPC5125, +}; + +/* + * This macro abstracts the differences in the PSC register layout between + * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc). + */ +#define psc_addr(mps, regname) ({ \ + void *__ret = NULL; \ + switch (mps->type) { \ + case TYPE_MPC5121: { \ + struct mpc52xx_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + case TYPE_MPC5125: { \ + struct mpc5125_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + } \ + __ret; }) + struct mpc512x_psc_spi { void (*cs_control)(struct spi_device *spi, bool on); - u32 sysclk; /* driver internal data */ - struct mpc52xx_psc __iomem *psc; + int type; + void __iomem *psc; struct mpc512x_psc_fifo __iomem *fifo; unsigned int irq; u8 bits_per_word; - u8 busy; - u32 mclk; - u8 eofbyte; - - struct workqueue_struct *workqueue; - struct work_struct work; + struct clk *clk_mclk; + struct clk *clk_ipg; + u32 mclk_rate; - struct list_head queue; - spinlock_t lock; /* Message queue lock */ - - struct completion done; + struct completion txisrdone; }; /* controller state */ @@ -79,12 +97,12 @@ { struct mpc512x_psc_spi_cs *cs = spi->controller_state; struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - struct mpc52xx_psc __iomem *psc = mps->psc; u32 sicr; u32 ccr; + int speed; u16 bclkdiv; - sicr = in_be32(&psc->sicr); + sicr = in_be32(psc_addr(mps, sicr)); /* Set clock phase and polarity */ if (spi->mode & SPI_CPHA) @@ -101,17 +119,17 @@ sicr |= 0x10000000; else sicr &= ~0x10000000; - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; - if (cs->speed_hz) - bclkdiv = (mps->mclk / cs->speed_hz) - 1; - else - bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */ + speed = cs->speed_hz; + if (!speed) + speed = 1000000; /* default 1MHz */ + bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); mps->bits_per_word = cs->bits_per_word; if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) @@ -136,145 +154,220 @@ struct spi_transfer *t) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; - size_t len = t->len; + size_t tx_len = t->len; + size_t rx_len = t->len; u8 *tx_buf = (u8 *)t->tx_buf; u8 *rx_buf = (u8 *)t->rx_buf; if (!tx_buf && !rx_buf && t->len) return -EINVAL; - /* Zero MR2 */ - in_8(&psc->mode); - out_8(&psc->mode, 0x0); - - /* enable transmiter/receiver */ - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); - - while (len) { - int count; - int i; + while (rx_len || tx_len) { + size_t txcount; u8 data; size_t fifosz; - int rxcount; + size_t rxcount; + int rxtries; /* - * The number of bytes that can be sent at a time - * depends on the fifo size. + * send the TX bytes in as large a chunk as possible + * but neither exceed the TX nor the RX FIFOs */ fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz)); - count = min(fifosz, len); + txcount = min(fifosz, tx_len); + fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz)); + fifosz -= in_be32(&fifo->rxcnt) + 1; + txcount = min(fifosz, txcount); + if (txcount) { + + /* fill the TX FIFO */ + while (txcount-- > 0) { + data = tx_buf ? *tx_buf++ : 0; + if (tx_len == EOFBYTE && t->cs_change) + setbits32(&fifo->txcmd, + MPC512x_PSC_FIFO_EOF); + out_8(&fifo->txdata_8, data); + tx_len--; + } - for (i = count; i > 0; i--) { - data = tx_buf ? *tx_buf++ : 0; - if (len == EOFBYTE && t->cs_change) - setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF); - out_8(&fifo->txdata_8, data); - len--; + /* have the ISR trigger when the TX FIFO is empty */ + reinit_completion(&mps->txisrdone); + out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); + out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); + wait_for_completion(&mps->txisrdone); } - INIT_COMPLETION(mps->done); - - /* interrupt on tx fifo empty */ - out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); - out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); - - wait_for_completion(&mps->done); + /* + * consume as much RX data as the FIFO holds, while we + * iterate over the transfer's TX data length + * + * only insist in draining all the remaining RX bytes + * when the TX bytes were exhausted (that's at the very + * end of this transfer, not when still iterating over + * the transfer's chunks) + */ + rxtries = 50; + do { - mdelay(1); + /* + * grab whatever was in the FIFO when we started + * looking, don't bother fetching what was added to + * the FIFO while we read from it -- we'll return + * here eventually and prefer sending out remaining + * TX data + */ + fifosz = in_be32(&fifo->rxcnt); + rxcount = min(fifosz, rx_len); + while (rxcount-- > 0) { + data = in_8(&fifo->rxdata_8); + if (rx_buf) + *rx_buf++ = data; + rx_len--; + } - /* rx fifo should have count bytes in it */ - rxcount = in_be32(&fifo->rxcnt); - if (rxcount != count) - mdelay(1); + /* + * come back later if there still is TX data to send, + * bail out of the RX drain loop if all of the TX data + * was sent and all of the RX data was received (i.e. + * when the transmission has completed) + */ + if (tx_len) + break; + if (!rx_len) + break; - rxcount = in_be32(&fifo->rxcnt); - if (rxcount != count) { - dev_warn(&spi->dev, "expected %d bytes in rx fifo " - "but got %d\n", count, rxcount); + /* + * TX data transmission has completed while RX data + * is still pending -- that's a transient situation + * which depends on wire speed and specific + * hardware implementation details (buffering) yet + * should resolve very quickly + * + * just yield for a moment to not hog the CPU for + * too long when running SPI at low speed + * + * the timeout range is rather arbitrary and tries + * to balance throughput against system load; the + * chosen values result in a minimal timeout of 50 + * times 10us and thus work at speeds as low as + * some 20kbps, while the maximum timeout at the + * transfer's end could be 5ms _if_ nothing else + * ticks in the system _and_ RX data still wasn't + * received, which only occurs in situations that + * are exceptional; removing the unpredictability + * of the timeout either decreases throughput + * (longer timeouts), or puts more load on the + * system (fixed short timeouts) or requires the + * use of a timeout API instead of a counter and an + * unknown inner delay + */ + usleep_range(10, 100); + + } while (--rxtries > 0); + if (!tx_len && rx_len && !rxtries) { + /* + * not enough RX bytes even after several retries + * and the resulting rather long timeout? + */ + rxcount = in_be32(&fifo->rxcnt); + dev_warn(&spi->dev, + "short xfer, missing %zd RX bytes, FIFO level %zd\n", + rx_len, rxcount); } - rxcount = min(rxcount, count); - for (i = rxcount; i > 0; i--) { - data = in_8(&fifo->rxdata_8); - if (rx_buf) - *rx_buf++ = data; - } - while (in_be32(&fifo->rxcnt)) { - in_8(&fifo->rxdata_8); + /* + * drain and drop RX data which "should not be there" in + * the first place, for undisturbed transmission this turns + * into a NOP (except for the FIFO level fetch) + */ + if (!tx_len && !rx_len) { + while (in_be32(&fifo->rxcnt)) + in_8(&fifo->rxdata_8); } + } - /* disable transmiter/receiver and fifo interrupt */ - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); - out_be32(&fifo->tximr, 0); return 0; } -static void mpc512x_psc_spi_work(struct work_struct *work) +static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, + struct spi_message *m) { - struct mpc512x_psc_spi *mps = container_of(work, - struct mpc512x_psc_spi, - work); - - spin_lock_irq(&mps->lock); - mps->busy = 1; - while (!list_empty(&mps->queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - unsigned cs_change; - int status; - - m = container_of(mps->queue.next, struct spi_message, queue); - list_del_init(&m->queue); - spin_unlock_irq(&mps->lock); - - spi = m->spi; - cs_change = 1; - status = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - status = mpc512x_psc_spi_transfer_setup(spi, t); - if (status < 0) - break; - } + struct spi_device *spi; + unsigned cs_change; + int status; + struct spi_transfer *t; + + spi = m->spi; + cs_change = 1; + status = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + status = mpc512x_psc_spi_transfer_setup(spi, t); + if (status < 0) + break; + + if (cs_change) + mpc512x_psc_spi_activate_cs(spi); + cs_change = t->cs_change; + + status = mpc512x_psc_spi_transfer_rxtx(spi, t); + if (status) + break; + m->actual_length += t->len; - if (cs_change) - mpc512x_psc_spi_activate_cs(spi); - cs_change = t->cs_change; + if (t->delay_usecs) + udelay(t->delay_usecs); - status = mpc512x_psc_spi_transfer_rxtx(spi, t); - if (status) - break; - m->actual_length += t->len; + if (cs_change) + mpc512x_psc_spi_deactivate_cs(spi); + } + + m->status = status; + if (m->complete) + m->complete(m->context); - if (t->delay_usecs) - udelay(t->delay_usecs); + if (status || !cs_change) + mpc512x_psc_spi_deactivate_cs(spi); - if (cs_change) - mpc512x_psc_spi_deactivate_cs(spi); - } + mpc512x_psc_spi_transfer_setup(spi, NULL); - m->status = status; - m->complete(m->context); + spi_finalize_current_message(master); + return status; +} - if (status || !cs_change) - mpc512x_psc_spi_deactivate_cs(spi); +static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) +{ + struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - mpc512x_psc_spi_transfer_setup(spi, NULL); + dev_dbg(&master->dev, "%s()\n", __func__); - spin_lock_irq(&mps->lock); - } - mps->busy = 0; - spin_unlock_irq(&mps->lock); + /* Zero MR2 */ + in_8(psc_addr(mps, mr2)); + out_8(psc_addr(mps, mr2), 0x0); + + /* enable transmitter/receiver */ + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + + return 0; +} + +static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) +{ + struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); + struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; + + dev_dbg(&master->dev, "%s()\n", __func__); + + /* disable transmitter/receiver and fifo interrupt */ + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_be32(&fifo->tximr, 0); + + return 0; } static int mpc512x_psc_spi_setup(struct spi_device *spi) { - struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); struct mpc512x_psc_spi_cs *cs = spi->controller_state; - unsigned long flags; int ret; if (spi->bits_per_word % 8) @@ -303,28 +396,6 @@ cs->bits_per_word = spi->bits_per_word; cs->speed_hz = spi->max_speed_hz; - spin_lock_irqsave(&mps->lock, flags); - if (!mps->busy) - mpc512x_psc_spi_deactivate_cs(spi); - spin_unlock_irqrestore(&mps->lock, flags); - - return 0; -} - -static int mpc512x_psc_spi_transfer(struct spi_device *spi, - struct spi_message *m) -{ - struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - unsigned long flags; - - m->actual_length = 0; - m->status = -EINPROGRESS; - - spin_lock_irqsave(&mps->lock, flags); - list_add_tail(&m->queue, &mps->queue); - queue_work(mps->workqueue, &mps->work); - spin_unlock_irqrestore(&mps->lock, flags); - return 0; } @@ -338,28 +409,19 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, struct mpc512x_psc_spi *mps) { - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; - struct clk *spiclk; - int ret = 0; - char name[32]; u32 sicr; u32 ccr; + int speed; u16 bclkdiv; - sprintf(name, "psc%d_mclk", master->bus_num); - spiclk = clk_get(&master->dev, name); - clk_enable(spiclk); - mps->mclk = clk_get_rate(spiclk); - clk_put(spiclk); - /* Reset the PSC into a known state */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); /* Disable psc interrupts all useful interrupts are in fifo */ - out_be16(&psc->isr_imr.imr, 0); + out_be16(psc_addr(mps, isr_imr.imr), 0); /* Disable fifo interrupts, will be enabled later */ out_be32(&fifo->tximr, 0); @@ -375,17 +437,18 @@ 0x00004000 | /* MSTR = 1 -- SPI master */ 0x00000800; /* UseEOF = 1 -- SS low until EOF */ - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; - bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */ + speed = 1000000; /* default 1MHz */ + bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); /* Set 2ms DTL delay */ - out_8(&psc->ctur, 0x00); - out_8(&psc->ctlr, 0x82); + out_8(psc_addr(mps, ctur), 0x00); + out_8(psc_addr(mps, ctlr), 0x82); /* we don't use the alarms */ out_be32(&fifo->rxalarm, 0xfff); @@ -399,7 +462,7 @@ mps->bits_per_word = 8; - return ret; + return 0; } static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id) @@ -407,12 +470,12 @@ struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; - /* clear interrupt and wake up the work queue */ + /* clear interrupt and wake up the rx/tx routine */ if (in_be32(&fifo->txisr) & in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) { out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); out_be32(&fifo->tximr, 0); - complete(&mps->done); + complete(&mps->txisrdone); return IRQ_HANDLED; } return IRQ_NONE; @@ -423,16 +486,15 @@ gpio_set_value(spi->cs_gpio, onoff); } -/* bus_num is used only for the case dev->platform_data == NULL */ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, - u32 size, unsigned int irq, - s16 bus_num) + u32 size, unsigned int irq) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc512x_psc_spi *mps; struct spi_master *master; int ret; void *tempp; + struct clk *clk; master = spi_alloc_master(dev, sizeof *mps); if (master == NULL) @@ -440,26 +502,26 @@ dev_set_drvdata(dev, master); mps = spi_master_get_devdata(master); + mps->type = (int)of_device_get_match_data(dev); mps->irq = irq; if (pdata == NULL) { mps->cs_control = mpc512x_spi_cs_control; - mps->sysclk = 0; - master->bus_num = bus_num; } else { mps->cs_control = pdata->cs_control; - mps->sysclk = pdata->sysclk; master->bus_num = pdata->bus_num; master->num_chipselect = pdata->max_chipselect; } master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; master->setup = mpc512x_psc_spi_setup; - master->transfer = mpc512x_psc_spi_transfer; + master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw; + master->transfer_one_message = mpc512x_psc_spi_msg_xfer; + master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw; master->cleanup = mpc512x_psc_spi_cleanup; master->dev.of_node = dev->of_node; - tempp = ioremap(regaddr, size); + tempp = devm_ioremap(dev, regaddr, size); if (!tempp) { dev_err(dev, "could not ioremap I/O port range\n"); ret = -EFAULT; @@ -468,41 +530,48 @@ mps->psc = tempp; mps->fifo = (struct mpc512x_psc_fifo *)(tempp + sizeof(struct mpc52xx_psc)); + ret = devm_request_irq(dev, mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED, + "mpc512x-psc-spi", mps); + if (ret) + goto free_master; + init_completion(&mps->txisrdone); - ret = request_irq(mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED, - "mpc512x-psc-spi", mps); + clk = devm_clk_get(dev, "mclk"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto free_master; + } + ret = clk_prepare_enable(clk); if (ret) goto free_master; + mps->clk_mclk = clk; + mps->mclk_rate = clk_get_rate(clk); + + clk = devm_clk_get(dev, "ipg"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto free_mclk_clock; + } + ret = clk_prepare_enable(clk); + if (ret) + goto free_mclk_clock; + mps->clk_ipg = clk; ret = mpc512x_psc_spi_port_config(master, mps); if (ret < 0) - goto free_irq; + goto free_ipg_clock; - spin_lock_init(&mps->lock); - init_completion(&mps->done); - INIT_WORK(&mps->work, mpc512x_psc_spi_work); - INIT_LIST_HEAD(&mps->queue); - - mps->workqueue = - create_singlethread_workqueue(dev_name(master->dev.parent)); - if (mps->workqueue == NULL) { - ret = -EBUSY; - goto free_irq; - } - - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret < 0) - goto unreg_master; + goto free_ipg_clock; return ret; -unreg_master: - destroy_workqueue(mps->workqueue); -free_irq: - free_irq(mps->irq, mps); +free_ipg_clock: + clk_disable_unprepare(mps->clk_ipg); +free_mclk_clock: + clk_disable_unprepare(mps->clk_mclk); free_master: - if (mps->psc) - iounmap(mps->psc); spi_master_put(master); return ret; @@ -510,16 +579,11 @@ static int mpc512x_psc_spi_do_remove(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - flush_workqueue(mps->workqueue); - destroy_workqueue(mps->workqueue); - spi_unregister_master(master); - free_irq(mps->irq, mps); - if (mps->psc) - iounmap(mps->psc); - spi_master_put(master); + clk_disable_unprepare(mps->clk_mclk); + clk_disable_unprepare(mps->clk_ipg); return 0; } @@ -528,7 +592,6 @@ { const u32 *regaddr_p; u64 regaddr64, size64; - s16 id = -1; regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { @@ -537,16 +600,8 @@ } regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); - /* get PSC id (0..11, used by port_config) */ - id = of_alias_get_id(op->dev.of_node, "spi"); - if (id < 0) { - dev_err(&op->dev, "no alias id for %s\n", - op->dev.of_node->full_name); - return id; - } - return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64, - irq_of_parse_and_map(op->dev.of_node, 0), id); + irq_of_parse_and_map(op->dev.of_node, 0)); } static int mpc512x_psc_spi_of_remove(struct platform_device *op) @@ -554,8 +609,9 @@ return mpc512x_psc_spi_do_remove(&op->dev); } -static struct of_device_id mpc512x_psc_spi_of_match[] = { - { .compatible = "fsl,mpc5121-psc-spi", }, +static const struct of_device_id mpc512x_psc_spi_of_match[] = { + { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 }, + { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 }, {}, }; @@ -566,7 +622,6 @@ .remove = mpc512x_psc_spi_of_remove, .driver = { .name = "mpc512x-psc-spi", - .owner = THIS_MODULE, .of_match_table = mpc512x_psc_spi_of_match, }, };