blob: ef2c40da27c055ac22d11cbd34da490f45e6f533 [file] [log] [blame]
Anup Patel7a167f22019-02-25 08:15:19 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2019 Western Digital Corporation or its affiliates.
4 *
5 * Authors:
6 * Anup Patel <anup.patel@wdc.com>
7 */
8
Anup Patel7a167f22019-02-25 08:15:19 +00009#include <dm.h>
Simon Glassed38aef2020-05-10 11:40:03 -060010#include <env.h>
Simon Glass97589732020-05-10 11:40:02 -060011#include <init.h>
Pragnesh Patel2a449a32020-05-29 11:33:22 +053012#include <log.h>
Simon Glassc06c1be2020-05-10 11:40:08 -060013#include <linux/bug.h>
Anup Pateldb132102019-06-25 06:31:44 +000014#include <linux/delay.h>
15#include <linux/io.h>
Pragnesh Patel2a449a32020-05-29 11:33:22 +053016#include <misc.h>
Anup Pateldb132102019-06-25 06:31:44 +000017
Pragnesh Patel2a449a32020-05-29 11:33:22 +053018/*
19 * This define is a value used for error/unknown serial.
20 * If we really care about distinguishing errors and 0 is
21 * valid, we'll need a different one.
22 */
23#define ERROR_READING_SERIAL_NUMBER 0
Anup Pateldb132102019-06-25 06:31:44 +000024
Pragnesh Patel2a449a32020-05-29 11:33:22 +053025#ifdef CONFIG_MISC_INIT_R
Anup Pateldb132102019-06-25 06:31:44 +000026
Pragnesh Patel2a449a32020-05-29 11:33:22 +053027#if CONFIG_IS_ENABLED(SIFIVE_OTP)
28static u32 otp_read_serialnum(struct udevice *dev)
Anup Pateldb132102019-06-25 06:31:44 +000029{
Pragnesh Patel2a449a32020-05-29 11:33:22 +053030 int ret;
31 u32 serial[2] = {0};
Anup Pateldb132102019-06-25 06:31:44 +000032
Pragnesh Patel2a449a32020-05-29 11:33:22 +053033 for (int i = 0xfe * 4; i > 0; i -= 8) {
34 ret = misc_read(dev, i, serial, sizeof(serial));
Anup Pateldb132102019-06-25 06:31:44 +000035
Pragnesh Patel2a449a32020-05-29 11:33:22 +053036 if (ret != sizeof(serial)) {
37 printf("%s: error reading serial from OTP\n", __func__);
38 break;
39 }
Anup Pateldb132102019-06-25 06:31:44 +000040
Pragnesh Patel2a449a32020-05-29 11:33:22 +053041 if (serial[0] == ~serial[1])
42 return serial[0];
Anup Pateldb132102019-06-25 06:31:44 +000043 }
44
Pragnesh Patel2a449a32020-05-29 11:33:22 +053045 return ERROR_READING_SERIAL_NUMBER;
Anup Pateldb132102019-06-25 06:31:44 +000046}
Pragnesh Patel2a449a32020-05-29 11:33:22 +053047#endif
Anup Pateldb132102019-06-25 06:31:44 +000048
49static u32 fu540_read_serialnum(void)
50{
Pragnesh Patel2a449a32020-05-29 11:33:22 +053051 u32 serial = ERROR_READING_SERIAL_NUMBER;
52
53#if CONFIG_IS_ENABLED(SIFIVE_OTP)
54 struct udevice *dev;
Anup Pateldb132102019-06-25 06:31:44 +000055 int ret;
Anup Pateldb132102019-06-25 06:31:44 +000056
Pragnesh Patel2a449a32020-05-29 11:33:22 +053057 /* init OTP */
58 ret = uclass_get_device_by_driver(UCLASS_MISC,
59 DM_GET_DRIVER(sifive_otp), &dev);
60
61 if (ret) {
62 debug("%s: could not find otp device\n", __func__);
63 return serial;
Anup Pateldb132102019-06-25 06:31:44 +000064 }
65
Pragnesh Patel2a449a32020-05-29 11:33:22 +053066 /* read serial from OTP and set env var */
67 serial = otp_read_serialnum(dev);
68#endif
69
70 return serial;
Anup Pateldb132102019-06-25 06:31:44 +000071}
72
73static void fu540_setup_macaddr(u32 serialnum)
74{
75 /* Default MAC address */
76 unsigned char mac[6] = { 0x70, 0xb3, 0xd5, 0x92, 0xf0, 0x00 };
77
78 /*
79 * We derive our board MAC address by ORing last three bytes
80 * of board serial number to above default MAC address.
81 *
82 * This logic of deriving board MAC address is taken from
83 * SiFive FSBL and is kept unchanged.
84 */
85 mac[5] |= (serialnum >> 0) & 0xff;
86 mac[4] |= (serialnum >> 8) & 0xff;
87 mac[3] |= (serialnum >> 16) & 0xff;
88
89 /* Update environment variable */
90 eth_env_set_enetaddr("ethaddr", mac);
91}
92
93int misc_init_r(void)
94{
Sagar Shrikant Kadam45309b22019-08-12 07:57:40 -070095 u32 serial_num;
96 char buf[9] = {0};
Anup Pateldb132102019-06-25 06:31:44 +000097
Sagar Shrikant Kadam45309b22019-08-12 07:57:40 -070098 /* Set ethaddr environment variable from board serial number */
99 if (!env_get("serial#")) {
100 serial_num = fu540_read_serialnum();
101 if (!serial_num) {
102 WARN(true, "Board serial number should not be 0 !!\n");
103 return 0;
104 }
105 snprintf(buf, sizeof(buf), "%08x", serial_num);
106 env_set("serial#", buf);
107 fu540_setup_macaddr(serial_num);
108 }
Anup Pateldb132102019-06-25 06:31:44 +0000109 return 0;
110}
111
112#endif
Anup Patel7a167f22019-02-25 08:15:19 +0000113
114int board_init(void)
115{
116 /* For now nothing to do here. */
117
118 return 0;
119}