~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 6016f6daef95b330a40e638dcc30e01e83bc0fae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: GPL-2.0+
/*
 * V3HSK board CPLD access support
 *
 * Copyright (C) 2019 Renesas Electronics Corporation
 * Copyright (C) 2019 Cogent Embedded, Inc.
 *
 */

#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <linux/err.h>
#include <sysreset.h>
#include <command.h>

#define CPLD_ADDR_PRODUCT_0		0x0000 /* R */
#define CPLD_ADDR_PRODUCT_1		0x0001 /* R */
#define CPLD_ADDR_PRODUCT_2		0x0002 /* R */
#define CPLD_ADDR_PRODUCT_3		0x0003 /* R */
#define CPLD_ADDR_CPLD_VERSION_D	0x0004 /* R */
#define CPLD_ADDR_CPLD_VERSION_M	0x0005 /* R */
#define CPLD_ADDR_CPLD_VERSION_Y_0	0x0006 /* R */
#define CPLD_ADDR_CPLD_VERSION_Y_1	0x0007 /* R */
#define CPLD_ADDR_MODE_SET_0		0x0008 /* R */
#define CPLD_ADDR_MODE_SET_1		0x0009 /* R */
#define CPLD_ADDR_MODE_SET_2		0x000A /* R */
#define CPLD_ADDR_MODE_SET_3		0x000B /* R */
#define CPLD_ADDR_MODE_SET_4		0x000C /* R */
#define CPLD_ADDR_MODE_LAST_0		0x0018 /* R */
#define CPLD_ADDR_MODE_LAST_1		0x0019 /* R */
#define CPLD_ADDR_MODE_LAST_2		0x001A /* R */
#define CPLD_ADDR_MODE_LAST_3		0x001B /* R */
#define CPLD_ADDR_MODE_LAST_4		0x001C /* R */
#define CPLD_ADDR_DIPSW4		0x0020 /* R */
#define CPLD_ADDR_DIPSW5		0x0021 /* R */
#define CPLD_ADDR_RESET			0x0024 /* R/W */
#define CPLD_ADDR_POWER_CFG		0x0025 /* R/W */
#define CPLD_ADDR_PERI_CFG_0		0x0030 /* R/W */
#define CPLD_ADDR_PERI_CFG_1		0x0031 /* R/W */
#define CPLD_ADDR_PERI_CFG_2		0x0032 /* R/W */
#define CPLD_ADDR_PERI_CFG_3		0x0033 /* R/W */
#define CPLD_ADDR_LEDS			0x0034 /* R/W */
#define CPLD_ADDR_LEDS_CFG		0x0035 /* R/W */
#define CPLD_ADDR_UART_CFG		0x0036 /* R/W */
#define CPLD_ADDR_UART_STATUS		0x0037 /* R */

#define CPLD_ADDR_PCB_VERSION_0		0x1000 /* R */
#define CPLD_ADDR_PCB_VERSION_1		0x1001 /* R */
#define CPLD_ADDR_SOC_VERSION_0		0x1002 /* R */
#define CPLD_ADDR_SOC_VERSION_1		0x1003 /* R */
#define CPLD_ADDR_PCB_SN_0		0x1004 /* R */
#define CPLD_ADDR_PCB_SN_1		0x1005 /* R */

static u16 cpld_read(struct udevice *dev, u16 addr)
{
	u8 data[2];

	/* Random flash reads require 2 reads: first read is unreliable */
	if (addr >= CPLD_ADDR_PCB_VERSION_0)
		dm_i2c_read(dev, addr, data, 2);

	/* Only the second byte read is valid */
	dm_i2c_read(dev, addr, data, 2);
	return data[1];
}

static void cpld_write(struct udevice *dev, u16 addr, u8 data)
{
	dm_i2c_write(dev, addr, &data, 1);
}

static int do_cpld(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
{
	struct udevice *dev;
	u16 addr, val;
	int ret;

	ret = uclass_get_device_by_driver(UCLASS_SYSRESET,
					  DM_DRIVER_GET(sysreset_renesas_v3hsk),
					  &dev);
	if (ret)
		return ret;

	if (argc == 2 && strcmp(argv[1], "info") == 0) {
		printf("Product:                0x%08x\n",
		       (cpld_read(dev, CPLD_ADDR_PRODUCT_3) << 24) |
		       (cpld_read(dev, CPLD_ADDR_PRODUCT_2) << 16) |
		       (cpld_read(dev, CPLD_ADDR_PRODUCT_1) << 8) |
		       cpld_read(dev, CPLD_ADDR_PRODUCT_0));
		printf("CPLD version:           0x%08x\n",
		       (cpld_read(dev, CPLD_ADDR_CPLD_VERSION_Y_1) << 24) |
		       (cpld_read(dev, CPLD_ADDR_CPLD_VERSION_Y_0) << 16) |
		       (cpld_read(dev, CPLD_ADDR_CPLD_VERSION_M) << 8) |
		       cpld_read(dev, CPLD_ADDR_CPLD_VERSION_D));
		printf("Mode setting (MD0..26): 0x%08x\n",
		       (cpld_read(dev, CPLD_ADDR_MODE_LAST_3) << 24) |
		       (cpld_read(dev, CPLD_ADDR_MODE_LAST_2) << 16) |
		       (cpld_read(dev, CPLD_ADDR_MODE_LAST_1) << 8) |
		       cpld_read(dev, CPLD_ADDR_MODE_LAST_0));
		printf("DIPSW (SW4, SW5):       0x%02x, 0x%x\n",
		       cpld_read(dev, CPLD_ADDR_DIPSW4) ^ 0xff,
		       (cpld_read(dev, CPLD_ADDR_DIPSW5) ^ 0xff) & 0xf);
		printf("Power config:           0x%08x\n",
		       cpld_read(dev, CPLD_ADDR_POWER_CFG));
		printf("Periferals config:      0x%08x\n",
		       (cpld_read(dev, CPLD_ADDR_PERI_CFG_3) << 24) |
		       (cpld_read(dev, CPLD_ADDR_PERI_CFG_2) << 16) |
		       (cpld_read(dev, CPLD_ADDR_PERI_CFG_1) << 8) |
		       cpld_read(dev, CPLD_ADDR_PERI_CFG_0));
		printf("PCB version:            %d.%d\n",
		       cpld_read(dev, CPLD_ADDR_PCB_VERSION_1),
		       cpld_read(dev, CPLD_ADDR_PCB_VERSION_0));
		printf("SOC version:            %d.%d\n",
		       cpld_read(dev, CPLD_ADDR_SOC_VERSION_1),
		       cpld_read(dev, CPLD_ADDR_SOC_VERSION_0));
		printf("PCB S/N:                %d\n",
		       (cpld_read(dev, CPLD_ADDR_PCB_SN_1) << 8) |
		       cpld_read(dev, CPLD_ADDR_PCB_SN_0));
		return 0;
	}

	if (argc < 3)
		return CMD_RET_USAGE;

	addr = simple_strtoul(argv[2], NULL, 16);
	if (!(addr >= CPLD_ADDR_PRODUCT_0 && addr <= CPLD_ADDR_UART_STATUS)) {
		printf("cpld invalid addr\n");
		return CMD_RET_USAGE;
	}

	if (argc == 3 && strcmp(argv[1], "read") == 0) {
		printf("0x%x\n", cpld_read(dev, addr));
	} else if (argc == 4 && strcmp(argv[1], "write") == 0) {
		val = simple_strtoul(argv[3], NULL, 16);
		cpld_write(dev, addr, val);
	}

	return 0;
}

U_BOOT_CMD(cpld, 4, 1, do_cpld,
	   "CPLD access",
	   "info\n"
	   "cpld read addr\n"
	   "cpld write addr val\n"
);

static int renesas_v3hsk_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
	cpld_write(dev, CPLD_ADDR_RESET, 1);

	return -EINPROGRESS;
}

static int renesas_v3hsk_sysreset_probe(struct udevice *dev)
{
	if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
		return -EPROTONOSUPPORT;

	return 0;
}

static struct sysreset_ops renesas_v3hsk_sysreset = {
	.request	= renesas_v3hsk_sysreset_request,
};

static const struct udevice_id renesas_v3hsk_sysreset_ids[] = {
	{ .compatible = "renesas,v3hsk-cpld" },
	{ /* sentinel */ }
};

U_BOOT_DRIVER(sysreset_renesas_v3hsk) = {
	.name		= "renesas_v3hsk_sysreset",
	.id		= UCLASS_SYSRESET,
	.ops		= &renesas_v3hsk_sysreset,
	.probe		= renesas_v3hsk_sysreset_probe,
	.of_match	= renesas_v3hsk_sysreset_ids,
};