463-spi-ath79-add-fast-flash-read.patch 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. --- a/drivers/spi/spi-ath79.c
  2. +++ b/drivers/spi/spi-ath79.c
  3. @@ -35,6 +35,11 @@
  4. #define ATH79_SPI_CS_LINE_MAX 2
  5. +enum ath79_spi_state {
  6. + ATH79_SPI_STATE_WAIT_CMD = 0,
  7. + ATH79_SPI_STATE_WAIT_READ,
  8. +};
  9. +
  10. struct ath79_spi {
  11. struct spi_bitbang bitbang;
  12. u32 ioc_base;
  13. @@ -42,6 +47,11 @@ struct ath79_spi {
  14. void __iomem *base;
  15. struct clk *clk;
  16. unsigned rrw_delay;
  17. +
  18. + enum ath79_spi_state state;
  19. + u32 clk_div;
  20. + unsigned long read_addr;
  21. + unsigned long ahb_rate;
  22. };
  23. static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
  24. @@ -109,9 +119,6 @@ static void ath79_spi_enable(struct ath7
  25. /* save CTRL register */
  26. sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
  27. sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
  28. -
  29. - /* TODO: setup speed? */
  30. - ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
  31. }
  32. static void ath79_spi_disable(struct ath79_spi *sp)
  33. @@ -224,6 +231,110 @@ static u32 ath79_spi_txrx_mode0(struct s
  34. return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
  35. }
  36. +static int ath79_spi_do_read_flash_data(struct spi_device *spi,
  37. + struct spi_transfer *t)
  38. +{
  39. + struct ath79_spi *sp = ath79_spidev_to_sp(spi);
  40. +
  41. + /* disable GPIO mode */
  42. + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
  43. +
  44. + memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
  45. +
  46. + /* enable GPIO mode */
  47. + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
  48. +
  49. + /* restore IOC register */
  50. + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
  51. +
  52. + return t->len;
  53. +}
  54. +
  55. +static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
  56. + struct spi_transfer *t)
  57. +{
  58. + struct ath79_spi *sp = ath79_spidev_to_sp(spi);
  59. + int len;
  60. + const u8 *p;
  61. +
  62. + sp->read_addr = 0;
  63. +
  64. + len = t->len - 1;
  65. + p = t->tx_buf;
  66. +
  67. + while (len--) {
  68. + p++;
  69. + sp->read_addr <<= 8;
  70. + sp->read_addr |= *p;
  71. + }
  72. +
  73. + return t->len;
  74. +}
  75. +
  76. +static bool ath79_spi_is_read_cmd(struct spi_device *spi,
  77. + struct spi_transfer *t)
  78. +{
  79. + return t->type == SPI_TRANSFER_FLASH_READ_CMD;
  80. +}
  81. +
  82. +static bool ath79_spi_is_data_read(struct spi_device *spi,
  83. + struct spi_transfer *t)
  84. +{
  85. + return t->type == SPI_TRANSFER_FLASH_READ_DATA;
  86. +}
  87. +
  88. +static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
  89. +{
  90. + struct ath79_spi *sp = ath79_spidev_to_sp(spi);
  91. + int ret;
  92. +
  93. + switch (sp->state) {
  94. + case ATH79_SPI_STATE_WAIT_CMD:
  95. + if (ath79_spi_is_read_cmd(spi, t)) {
  96. + ret = ath79_spi_do_read_flash_cmd(spi, t);
  97. + sp->state = ATH79_SPI_STATE_WAIT_READ;
  98. + } else {
  99. + ret = spi_bitbang_bufs(spi, t);
  100. + }
  101. + break;
  102. +
  103. + case ATH79_SPI_STATE_WAIT_READ:
  104. + if (ath79_spi_is_data_read(spi, t)) {
  105. + ret = ath79_spi_do_read_flash_data(spi, t);
  106. + } else {
  107. + dev_warn(&spi->dev, "flash data read expected\n");
  108. + ret = -EIO;
  109. + }
  110. + sp->state = ATH79_SPI_STATE_WAIT_CMD;
  111. + break;
  112. +
  113. + default:
  114. + BUG();
  115. + }
  116. +
  117. + return ret;
  118. +}
  119. +
  120. +static int ath79_spi_setup_transfer(struct spi_device *spi,
  121. + struct spi_transfer *t)
  122. +{
  123. + struct ath79_spi *sp = ath79_spidev_to_sp(spi);
  124. + struct ath79_spi_controller_data *cdata;
  125. + int ret;
  126. +
  127. + ret = spi_bitbang_setup_transfer(spi, t);
  128. + if (ret)
  129. + return ret;
  130. +
  131. + cdata = spi->controller_data;
  132. + if (cdata->is_flash)
  133. + sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
  134. + else
  135. + sp->bitbang.txrx_bufs = spi_bitbang_bufs;
  136. +
  137. + return ret;
  138. +}
  139. +
  140. static int ath79_spi_probe(struct platform_device *pdev)
  141. {
  142. struct spi_master *master;
  143. @@ -246,6 +357,8 @@ static int ath79_spi_probe(struct platfo
  144. sp = spi_master_get_devdata(master);
  145. platform_set_drvdata(pdev, sp);
  146. + sp->state = ATH79_SPI_STATE_WAIT_CMD;
  147. +
  148. master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
  149. master->setup = ath79_spi_setup;
  150. master->cleanup = ath79_spi_cleanup;
  151. @@ -255,7 +368,7 @@ static int ath79_spi_probe(struct platfo
  152. sp->bitbang.master = master;
  153. sp->bitbang.chipselect = ath79_spi_chipselect;
  154. sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
  155. - sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
  156. + sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
  157. sp->bitbang.flags = SPI_CS_HIGH;
  158. r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  159. @@ -280,7 +393,8 @@ static int ath79_spi_probe(struct platfo
  160. if (ret)
  161. goto err_put_master;
  162. - rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
  163. + sp->ahb_rate = clk_get_rate(sp->clk);
  164. + rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
  165. if (!rate) {
  166. ret = -EINVAL;
  167. goto err_clk_disable;
  168. --- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
  169. +++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
  170. @@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
  171. struct ath79_spi_controller_data {
  172. enum ath79_spi_cs_type cs_type;
  173. unsigned cs_line;
  174. + bool is_flash;
  175. };
  176. #endif /* _ATH79_SPI_PLATFORM_H */