2
0

432-drivers-spi-Add-support-for-dynamic-calibration.patch 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. From 2ade0172154e50c8a2bfd8634c6eff943cffea29 Mon Sep 17 00:00:00 2001
  2. From: "SkyLake.Huang" <[email protected]>
  3. Date: Thu, 23 Jun 2022 18:35:52 +0800
  4. Subject: [PATCH 2/6] drivers: spi: Add support for dynamic calibration
  5. Signed-off-by: SkyLake.Huang <[email protected]>
  6. ---
  7. drivers/spi/spi.c | 137 ++++++++++++++++++++++++++++++++++++++++
  8. include/linux/spi/spi.h | 42 ++++++++++++
  9. 2 files changed, 179 insertions(+)
  10. --- a/drivers/spi/spi.c
  11. +++ b/drivers/spi/spi.c
  12. @@ -1385,6 +1385,70 @@ static int spi_transfer_wait(struct spi_
  13. return 0;
  14. }
  15. +int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi,
  16. + int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv)
  17. +{
  18. + int datalen = ctlr->cal_rule->datalen;
  19. + int addrlen = ctlr->cal_rule->addrlen;
  20. + u8 *buf;
  21. + int ret;
  22. + int i;
  23. + struct list_head *cal_head, *listptr;
  24. + struct spi_cal_target *target;
  25. +
  26. + /* Calculate calibration result */
  27. + int hit_val, total_hit, origin;
  28. + bool hit;
  29. +
  30. + /* Make sure we can start calibration */
  31. + if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata)
  32. + return 0;
  33. +
  34. + buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL);
  35. + if(!buf)
  36. + return -ENOMEM;
  37. +
  38. + ret = ctlr->append_caldata(ctlr);
  39. + if (ret)
  40. + goto cal_end;
  41. +
  42. + cal_head = ctlr->cal_target;
  43. + list_for_each(listptr, cal_head) {
  44. + target = list_entry(listptr, struct spi_cal_target, list);
  45. +
  46. + hit = false;
  47. + hit_val = 0;
  48. + total_hit = 0;
  49. + origin = *target->cal_item;
  50. +
  51. + for(i=target->cal_min; i<=target->cal_max; i+=target->step) {
  52. + *target->cal_item = i;
  53. + ret = (*cal_read)(drv_priv, ctlr->cal_rule->addr, addrlen, buf, datalen);
  54. + if(ret)
  55. + break;
  56. + dev_dbg(&spi->dev, "controller cal item value: 0x%x\n", i);
  57. + if(memcmp(ctlr->cal_rule->match_data, buf, datalen * sizeof(u8)) == 0) {
  58. + hit = true;
  59. + hit_val += i;
  60. + total_hit++;
  61. + dev_dbg(&spi->dev, "golden data matches data read!\n");
  62. + }
  63. + }
  64. + if(hit) {
  65. + *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit);
  66. + dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item);
  67. + } else {
  68. + *target->cal_item = origin;
  69. + dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin);
  70. + }
  71. + }
  72. +
  73. +cal_end:
  74. + kfree(buf);
  75. + return ret? ret: 0;
  76. +}
  77. +EXPORT_SYMBOL_GPL(spi_do_calibration);
  78. +
  79. static void _spi_transfer_delay_ns(u32 ns)
  80. {
  81. if (!ns)
  82. @@ -2219,6 +2283,75 @@ void spi_flush_queue(struct spi_controll
  83. /*-------------------------------------------------------------------------*/
  84. #if defined(CONFIG_OF)
  85. +static inline void alloc_cal_data(struct list_head **cal_target,
  86. + struct spi_cal_rule **cal_rule, bool enable)
  87. +{
  88. + if(enable) {
  89. + *cal_target = kmalloc(sizeof(struct list_head), GFP_KERNEL);
  90. + INIT_LIST_HEAD(*cal_target);
  91. + *cal_rule = kmalloc(sizeof(struct spi_cal_rule), GFP_KERNEL);
  92. + } else {
  93. + kfree(*cal_target);
  94. + kfree(*cal_rule);
  95. + }
  96. +}
  97. +
  98. +static int of_spi_parse_cal_dt(struct spi_controller *ctlr, struct spi_device *spi,
  99. + struct device_node *nc)
  100. +{
  101. + u32 value;
  102. + int rc;
  103. + const char *cal_mode;
  104. +
  105. + rc = of_property_read_bool(nc, "spi-cal-enable");
  106. + if (rc)
  107. + alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, true);
  108. + else
  109. + return 0;
  110. +
  111. + rc = of_property_read_string(nc, "spi-cal-mode", &cal_mode);
  112. + if(!rc) {
  113. + if(strcmp("read-data", cal_mode) == 0){
  114. + ctlr->cal_rule->mode = SPI_CAL_READ_DATA;
  115. + } else if(strcmp("read-pp", cal_mode) == 0) {
  116. + ctlr->cal_rule->mode = SPI_CAL_READ_PP;
  117. + return 0;
  118. + } else if(strcmp("read-sfdp", cal_mode) == 0){
  119. + ctlr->cal_rule->mode = SPI_CAL_READ_SFDP;
  120. + return 0;
  121. + }
  122. + } else
  123. + goto err;
  124. +
  125. + ctlr->cal_rule->datalen = 0;
  126. + rc = of_property_read_u32(nc, "spi-cal-datalen", &value);
  127. + if(!rc && value > 0) {
  128. + ctlr->cal_rule->datalen = value;
  129. +
  130. + ctlr->cal_rule->match_data = kzalloc(value * sizeof(u8), GFP_KERNEL);
  131. + rc = of_property_read_u8_array(nc, "spi-cal-data",
  132. + ctlr->cal_rule->match_data, value);
  133. + if(rc)
  134. + kfree(ctlr->cal_rule->match_data);
  135. + }
  136. +
  137. + rc = of_property_read_u32(nc, "spi-cal-addrlen", &value);
  138. + if(!rc && value > 0) {
  139. + ctlr->cal_rule->addrlen = value;
  140. +
  141. + ctlr->cal_rule->addr = kzalloc(value * sizeof(u32), GFP_KERNEL);
  142. + rc = of_property_read_u32_array(nc, "spi-cal-addr",
  143. + ctlr->cal_rule->addr, value);
  144. + if(rc)
  145. + kfree(ctlr->cal_rule->addr);
  146. + }
  147. + return 0;
  148. +
  149. +err:
  150. + alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, false);
  151. + return 0;
  152. +}
  153. +
  154. static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
  155. struct device_node *nc)
  156. {
  157. @@ -2337,6 +2470,10 @@ of_register_spi_device(struct spi_contro
  158. if (rc)
  159. goto err_out;
  160. + rc = of_spi_parse_cal_dt(ctlr, spi, nc);
  161. + if (rc)
  162. + goto err_out;
  163. +
  164. /* Store a pointer to the node in the device structure */
  165. of_node_get(nc);
  166. spi->dev.of_node = nc;
  167. --- a/include/linux/spi/spi.h
  168. +++ b/include/linux/spi/spi.h
  169. @@ -318,6 +318,40 @@ struct spi_driver {
  170. struct device_driver driver;
  171. };
  172. +enum {
  173. + SPI_CAL_READ_DATA = 0,
  174. + SPI_CAL_READ_PP = 1, /* only for SPI-NAND */
  175. + SPI_CAL_READ_SFDP = 2, /* only for SPI-NOR */
  176. +};
  177. +
  178. +struct nand_addr {
  179. + unsigned int lun;
  180. + unsigned int plane;
  181. + unsigned int eraseblock;
  182. + unsigned int page;
  183. + unsigned int dataoffs;
  184. +};
  185. +
  186. +/**
  187. + * Read calibration rule from device dts node.
  188. + * Once calibration result matches the rule, we regard is as success.
  189. + */
  190. +struct spi_cal_rule {
  191. + int datalen;
  192. + u8 *match_data;
  193. + int addrlen;
  194. + u32 *addr;
  195. + int mode;
  196. +};
  197. +
  198. +struct spi_cal_target {
  199. + u32 *cal_item;
  200. + int cal_min; /* min of cal_item */
  201. + int cal_max; /* max of cal_item */
  202. + int step; /* Increase/decrease cal_item */
  203. + struct list_head list;
  204. +};
  205. +
  206. static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
  207. {
  208. return drv ? container_of(drv, struct spi_driver, driver) : NULL;
  209. @@ -703,6 +737,11 @@ struct spi_controller {
  210. void *dummy_rx;
  211. void *dummy_tx;
  212. + /* For calibration */
  213. + int (*append_caldata)(struct spi_controller *ctlr);
  214. + struct list_head *cal_target;
  215. + struct spi_cal_rule *cal_rule;
  216. +
  217. int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
  218. /*
  219. @@ -1510,6 +1549,9 @@ spi_register_board_info(struct spi_board
  220. { return 0; }
  221. #endif
  222. +extern int spi_do_calibration(struct spi_controller *ctlr,
  223. + struct spi_device *spi, int (*cal_read)(void *, u32 *, int, u8 *, int), void *drv_priv);
  224. +
  225. /* If you're hotplugging an adapter with devices (parport, usb, etc)
  226. * use spi_new_device() to describe each device. You can also call
  227. * spi_unregister_device() to start making that device vanish, but