1// SPDX-License-Identifier: GPL-2.0+
2/* (C) Copyright 2019 CompuLab, Ltd. <www.compulab.co.il> */
3
4#include <common.h>
5#include <i2c.h>
6#include <linux/kernel.h>
7#include <asm/arch/imx8mq_pins.h>
8#include <asm/mach-imx/gpio.h>
9#include <asm-generic/gpio.h>
10#include <asm/setup.h>
11#include <linux/delay.h>
12
13#ifdef CONFIG_SPL_BUILD
14
15#define CFG_SYS_I2C_EEPROM_ADDR_P1	0x51
16
17static iomux_v3_cfg_t const eeprom_pads[] = {
18	IMX8MQ_PAD_GPIO1_IO13__GPIO1_IO13 | MUX_PAD_CTRL(NO_PAD_CTRL),
19};
20
21#define EEPROM_WP_GPIO IMX_GPIO_NR(1, 13)
22
23static void cl_eeprom_we(int enable)
24{
25	static int done;
26
27	if (done) {
28		gpio_direction_output(EEPROM_WP_GPIO, enable);
29		return;
30	}
31
32	imx_iomux_v3_setup_multiple_pads(eeprom_pads, ARRAY_SIZE(eeprom_pads));
33	gpio_request(EEPROM_WP_GPIO, "eeprom_wp");
34	gpio_direction_output(EEPROM_WP_GPIO, enable);
35	done = 1;
36}
37
38static int cl_eeprom_read(uint offset, uchar *buf, int len)
39{
40	struct udevice *dev;
41	int ret;
42
43	ret = i2c_get_chip_for_busnum(1, CFG_SYS_I2C_EEPROM_ADDR_P1,
44				      CONFIG_SYS_I2C_EEPROM_ADDR_LEN, &dev);
45	if (ret) {
46		printf("%s: Cannot find EEPROM: %d\n", __func__, ret);
47		return ret;
48	}
49
50	return dm_i2c_read(dev, offset, buf, len);
51}
52
53static int cl_eeprom_write(uint offset, uchar *buf, int len)
54{
55	struct udevice *dev;
56	int ret;
57
58	cl_eeprom_we(1);
59
60	ret = i2c_get_chip_for_busnum(1, CFG_SYS_I2C_EEPROM_ADDR_P1,
61				      CONFIG_SYS_I2C_EEPROM_ADDR_LEN, &dev);
62	if (ret) {
63		printf("%s: Cannot find EEPROM: %d\n", __func__, ret);
64		return ret;
65	}
66
67	return dm_i2c_write(dev, offset, buf, len);
68}
69
70/* Reserved for fututre use area */
71#define BOARD_DDRINFO_OFFSET 0x40
72#define BOARD_DDR_SIZE 4
73static u32 board_ddrinfo = 0xdeadbeef;
74
75#define BOARD_DDRSUBIND_OFFSET 0x44
76#define BOARD_DDRSUBIND_SIZE 1
77static u8 board_ddrsubind = 0xff;
78
79#define BOARD_OSIZE_OFFSET 0x80
80#define BOARD_OSIZE_SIZE 4
81static u32 board_osize = 0xdeadbeef;
82
83#define BOARD_DDRINFO_VALID(A) ((A) != 0xdeadbeef)
84
85u32 cl_eeprom_get_ddrinfo(void)
86{
87	if (!BOARD_DDRINFO_VALID(board_ddrinfo)) {
88		if (cl_eeprom_read(BOARD_DDRINFO_OFFSET, (uchar *)&board_ddrinfo, BOARD_DDR_SIZE))
89			return 0;
90	}
91	return board_ddrinfo;
92};
93
94u32 cl_eeprom_set_ddrinfo(u32 ddrinfo)
95{
96	if (cl_eeprom_write(BOARD_DDRINFO_OFFSET, (uchar *)&ddrinfo, BOARD_DDR_SIZE))
97		return 0;
98
99	board_ddrinfo = ddrinfo;
100
101	return board_ddrinfo;
102};
103
104u8 cl_eeprom_get_subind(void)
105{
106	if (cl_eeprom_read(BOARD_DDRSUBIND_OFFSET, (uchar *)&board_ddrsubind, BOARD_DDRSUBIND_SIZE))
107		return 0xff;
108
109	return board_ddrsubind;
110};
111
112u8 cl_eeprom_set_subind(u8 ddrsubind)
113{
114	if (cl_eeprom_write(BOARD_DDRSUBIND_OFFSET, (uchar *)&ddrsubind, BOARD_DDRSUBIND_SIZE))
115		return 0xff;
116	board_ddrsubind = ddrsubind;
117
118	return board_ddrsubind;
119};
120
121/* override-size ifaces */
122u32 cl_eeprom_get_osize(void)
123{
124	if (cl_eeprom_read(BOARD_OSIZE_OFFSET, (uchar *)&board_osize, BOARD_OSIZE_SIZE))
125		return 0;
126
127	return board_osize;
128};
129#endif
130