Chuanhong Guo <gch981...@gmail.com> 于2018年12月6日周四 下午7:19写道:
>
> According to John Crispin (aka blogic) on IRC on Nov 26 2018:
> so basically i made cs1 work for MTK/labs when i built
> the linkit smart for them. the req-sheet said that cs1 should be proper
> duplex spi. however ....
> 1) the core will always send 1 byte before any transfer, this is the
> m25p80 command.
> 2) mode 3 is broken and bit reversed (?)
> 3) some bit are incorrectly wired in hw for mode2/3
> we wrote a test script and test for [0-0xffff] on all modes and certain
> bits are swizzled under certain conditions and it was not possible to
> fix this even using a hack.
> we then decided to use spi-gpio and i never removed the errornous code
> basically the spi is fecked for anything but half duplex spi mode0
> running a sflash on it
>
> The controller will always send some data from OPCODE register under half
> duplex mode before starting a full-duplex transfer, so the full-duplex
> mode is broken.
> This piece of code also make CS1 unavailable since it forces the
> broken full-duplex mode to be used on CS1.
>
> Signed-off-by: Chuanhong Guo <gch981...@gmail.com>
> ---
> Changes since v1:
> Quoted John's reply in commit message
> slightly modified code comment
>
> drivers/staging/mt7621-spi/spi-mt7621.c | 120 +++---------------------
> 1 file changed, 15 insertions(+), 105 deletions(-)
>
> diff --git a/drivers/staging/mt7621-spi/spi-mt7621.c
> b/drivers/staging/mt7621-spi/spi-mt7621.c
> index d045b5568e0f..f115a8bf652d 100644
> --- a/drivers/staging/mt7621-spi/spi-mt7621.c
> +++ b/drivers/staging/mt7621-spi/spi-mt7621.c
> @@ -86,16 +86,13 @@ static inline void mt7621_spi_write(struct mt7621_spi
> *rs, u32 reg, u32 val)
> iowrite32(val, rs->base + reg);
> }
>
> -static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
> +static void mt7621_spi_reset(struct mt7621_spi *rs)
> {
> u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
>
> master |= 7 << 29;
> master |= 1 << 2;
> - if (duplex)
> - master |= 1 << 10;
> - else
> - master &= ~(1 << 10);
> + master &= ~(1 << 10);
>
> mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
> rs->pending_write = 0;
> @@ -107,7 +104,7 @@ static void mt7621_spi_set_cs(struct spi_device *spi, int
> enable)
> int cs = spi->chip_select;
> u32 polar = 0;
>
> - mt7621_spi_reset(rs, cs);
> + mt7621_spi_reset(rs);
> if (enable)
> polar = BIT(cs);
> mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
> @@ -261,7 +258,7 @@ static void mt7621_spi_write_half_duplex(struct
> mt7621_spi *rs,
> rs->pending_write = len;
> }
>
> -static int mt7621_spi_transfer_half_duplex(struct spi_master *master,
> +static int mt7621_spi_transfer_one_message(struct spi_master *master,
> struct spi_message *m)
> {
> struct mt7621_spi *rs = spi_master_get_devdata(master);
> @@ -284,7 +281,16 @@ static int mt7621_spi_transfer_half_duplex(struct
> spi_master *master,
> mt7621_spi_set_cs(spi, 1);
> m->actual_length = 0;
> list_for_each_entry(t, &m->transfers, transfer_list) {
> - if (t->rx_buf)
> + if((t->rx_buf) && (t->tx_buf)) {
Sorry, checkpatch.pl complained about this. I'll send v3 later.
> + /* This controller will shift some extra data out
> + * of spi_opcode if (mosi_bit_cnt > 0) &&
> + * (cmd_bit_cnt == 0). So the claimed full-duplex
> + * support is broken since we have no way to read
> + * the MISO value during that bit.
> + */
> + status = -EIO;
> + goto msg_done;
> + } else if (t->rx_buf)
> mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
> else if (t->tx_buf)
> mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
> @@ -300,102 +306,6 @@ static int mt7621_spi_transfer_half_duplex(struct
> spi_master *master,
> return 0;
> }
>
> -static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
> - struct spi_message *m)
> -{
> - struct mt7621_spi *rs = spi_master_get_devdata(master);
> - struct spi_device *spi = m->spi;
> - unsigned int speed = spi->max_speed_hz;
> - struct spi_transfer *t = NULL;
> - int status = 0;
> - int i, len = 0;
> - int rx_len = 0;
> - u32 data[9] = { 0 };
> - u32 val = 0;
> -
> - mt7621_spi_wait_till_ready(rs);
> -
> - list_for_each_entry(t, &m->transfers, transfer_list) {
> - const u8 *buf = t->tx_buf;
> -
> - if (t->rx_buf)
> - rx_len += t->len;
> -
> - if (!buf)
> - continue;
> -
> - if (WARN_ON(len + t->len > 16)) {
> - status = -EIO;
> - goto msg_done;
> - }
> -
> - for (i = 0; i < t->len; i++, len++)
> - data[len / 4] |= buf[i] << (8 * (len & 3));
> - if (speed > t->speed_hz)
> - speed = t->speed_hz;
> - }
> -
> - if (WARN_ON(rx_len > 16)) {
> - status = -EIO;
> - goto msg_done;
> - }
> -
> - if (mt7621_spi_prepare(spi, speed)) {
> - status = -EIO;
> - goto msg_done;
> - }
> -
> - for (i = 0; i < len; i += 4)
> - mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
> -
> - val |= len * 8;
> - val |= (rx_len * 8) << 12;
> - mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
> -
> - mt7621_spi_set_cs(spi, 1);
> -
> - val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
> - val |= SPI_CTL_START;
> - mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
> -
> - mt7621_spi_wait_till_ready(rs);
> -
> - mt7621_spi_set_cs(spi, 0);
> -
> - for (i = 0; i < rx_len; i += 4)
> - data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i);
> -
> - m->actual_length = rx_len;
> -
> - len = 0;
> - list_for_each_entry(t, &m->transfers, transfer_list) {
> - u8 *buf = t->rx_buf;
> -
> - if (!buf)
> - continue;
> -
> - for (i = 0; i < t->len; i++, len++)
> - buf[i] = data[len / 4] >> (8 * (len & 3));
> - }
> -
> -msg_done:
> - m->status = status;
> - spi_finalize_current_message(master);
> -
> - return 0;
> -}
> -
> -static int mt7621_spi_transfer_one_message(struct spi_master *master,
> - struct spi_message *m)
> -{
> - struct spi_device *spi = m->spi;
> - int cs = spi->chip_select;
> -
> - if (cs)
> - return mt7621_spi_transfer_full_duplex(master, m);
> - return mt7621_spi_transfer_half_duplex(master, m);
> -}
> -
> static int mt7621_spi_setup(struct spi_device *spi)
> {
> struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
> @@ -478,7 +388,7 @@ static int mt7621_spi_probe(struct platform_device *pdev)
>
> device_reset(&pdev->dev);
>
> - mt7621_spi_reset(rs, 0);
> + mt7621_spi_reset(rs);
>
> return spi_register_master(master);
> }
> --
> 2.19.1
>
_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel