0014-riscv-sifive-fu540-Setup-ethaddr-env-variable-using-.patch 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. From fc7ee5955a7aafd972c93d6f9da9e862272a6822 Mon Sep 17 00:00:00 2001
  2. From: Anup Patel <anup.patel@wdc.com>
  3. Date: Wed, 19 Jun 2019 20:55:53 +0530
  4. Subject: [PATCH 14/21] riscv: sifive: fu540: Setup ethaddr env variable using
  5. OTP
  6. This patch extends SiFive FU540 board support to setup ethaddr
  7. env variable based on board serialnum read from OTP.
  8. Signed-off-by: Anup Patel <anup.patel@wdc.com>
  9. Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
  10. Upstream-Status: Submitted
  11. ---
  12. board/sifive/fu540/fu540.c | 122 +++++++++++++++++++++++++++++++++
  13. configs/sifive_fu540_defconfig | 1 +
  14. 2 files changed, 123 insertions(+)
  15. diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c
  16. index 5adc4a3d4a..11daf1a75a 100644
  17. --- a/board/sifive/fu540/fu540.c
  18. +++ b/board/sifive/fu540/fu540.c
  19. @@ -8,6 +8,128 @@
  20. #include <common.h>
  21. #include <dm.h>
  22. +#include <linux/delay.h>
  23. +#include <linux/io.h>
  24. +
  25. +#ifdef CONFIG_MISC_INIT_R
  26. +
  27. +#define FU540_OTP_BASE_ADDR 0x10070000
  28. +
  29. +struct fu540_otp_regs {
  30. + u32 pa; /* Address input */
  31. + u32 paio; /* Program address input */
  32. + u32 pas; /* Program redundancy cell selection input */
  33. + u32 pce; /* OTP Macro enable input */
  34. + u32 pclk; /* Clock input */
  35. + u32 pdin; /* Write data input */
  36. + u32 pdout; /* Read data output */
  37. + u32 pdstb; /* Deep standby mode enable input (active low) */
  38. + u32 pprog; /* Program mode enable input */
  39. + u32 ptc; /* Test column enable input */
  40. + u32 ptm; /* Test mode enable input */
  41. + u32 ptm_rep;/* Repair function test mode enable input */
  42. + u32 ptr; /* Test row enable input */
  43. + u32 ptrim; /* Repair function enable input */
  44. + u32 pwe; /* Write enable input (defines program cycle) */
  45. +} __packed;
  46. +
  47. +#define BYTES_PER_FUSE 4
  48. +#define NUM_FUSES 0x1000
  49. +
  50. +static int fu540_otp_read(int offset, void *buf, int size)
  51. +{
  52. + struct fu540_otp_regs *regs = (void __iomem *)FU540_OTP_BASE_ADDR;
  53. + unsigned int i;
  54. + int fuseidx = offset / BYTES_PER_FUSE;
  55. + int fusecount = size / BYTES_PER_FUSE;
  56. + u32 fusebuf[fusecount];
  57. +
  58. + /* check bounds */
  59. + if (offset < 0 || size < 0)
  60. + return -EINVAL;
  61. + if (fuseidx >= NUM_FUSES)
  62. + return -EINVAL;
  63. + if ((fuseidx + fusecount) > NUM_FUSES)
  64. + return -EINVAL;
  65. +
  66. + /* init OTP */
  67. + writel(0x01, &regs->pdstb); /* wake up from stand-by */
  68. + writel(0x01, &regs->ptrim); /* enable repair function */
  69. + writel(0x01, &regs->pce); /* enable input */
  70. +
  71. + /* read all requested fuses */
  72. + for (i = 0; i < fusecount; i++, fuseidx++) {
  73. + writel(fuseidx, &regs->pa);
  74. +
  75. + /* cycle clock to read */
  76. + writel(0x01, &regs->pclk);
  77. + mdelay(1);
  78. + writel(0x00, &regs->pclk);
  79. + mdelay(1);
  80. +
  81. + /* read the value */
  82. + fusebuf[i] = readl(&regs->pdout);
  83. + }
  84. +
  85. + /* shut down */
  86. + writel(0, &regs->pce);
  87. + writel(0, &regs->ptrim);
  88. + writel(0, &regs->pdstb);
  89. +
  90. + /* copy out */
  91. + memcpy(buf, fusebuf, size);
  92. +
  93. + return 0;
  94. +}
  95. +
  96. +static u32 fu540_read_serialnum(void)
  97. +{
  98. + int ret;
  99. + u32 serial[2] = {0};
  100. +
  101. + for (int i = 0xfe * 4; i > 0; i -= 8) {
  102. + ret = fu540_otp_read(i, serial, sizeof(serial));
  103. + if (ret) {
  104. + printf("%s: error reading from OTP\n", __func__);
  105. + break;
  106. + }
  107. + if (serial[0] == ~serial[1])
  108. + return serial[0];
  109. + }
  110. +
  111. + return 0;
  112. +}
  113. +
  114. +static void fu540_setup_macaddr(u32 serialnum)
  115. +{
  116. + /* Default MAC address */
  117. + unsigned char mac[6] = { 0x70, 0xb3, 0xd5, 0x92, 0xf0, 0x00 };
  118. +
  119. + /*
  120. + * We derive our board MAC address by ORing last three bytes
  121. + * of board serial number to above default MAC address.
  122. + *
  123. + * This logic of deriving board MAC address is taken from
  124. + * SiFive FSBL and is kept unchanged.
  125. + */
  126. + mac[5] |= (serialnum >> 0) & 0xff;
  127. + mac[4] |= (serialnum >> 8) & 0xff;
  128. + mac[3] |= (serialnum >> 16) & 0xff;
  129. +
  130. + /* Update environment variable */
  131. + eth_env_set_enetaddr("ethaddr", mac);
  132. +}
  133. +
  134. +int misc_init_r(void)
  135. +{
  136. + /* Set ethaddr environment variable if not set */
  137. + if (!env_get("ethaddr"))
  138. + fu540_setup_macaddr(fu540_read_serialnum());
  139. +
  140. + return 0;
  141. +}
  142. +
  143. +#endif
  144. int board_init(void)
  145. {
  146. diff --git a/configs/sifive_fu540_defconfig b/configs/sifive_fu540_defconfig
  147. index f78412398e..f19203745e 100644
  148. --- a/configs/sifive_fu540_defconfig
  149. +++ b/configs/sifive_fu540_defconfig
  150. @@ -7,4 +7,5 @@ CONFIG_DISTRO_DEFAULTS=y
  151. CONFIG_FIT=y
  152. CONFIG_DISPLAY_CPUINFO=y
  153. CONFIG_DISPLAY_BOARDINFO=y
  154. +CONFIG_MISC_INIT_R=y
  155. CONFIG_OF_PRIOR_STAGE=y
  156. --
  157. 2.22.0