summaryrefslogtreecommitdiff
path: root/board/renesas/stout/cpld.c
blob: 5640e1d28e487b3cfd6f888e6f5fdd3537b2372b (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
/*
 * Stout board CPLD access support
 *
 * Copyright (C) 2015 Renesas Electronics Europe GmbH
 * Copyright (C) 2015 Renesas Electronics Corporation
 * Copyright (C) 2015 Cogent Embedded, Inc.
 *
 * SPDX-License-Identifier: GPL-2.0
 */

#include <common.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include "cpld.h"

#define SCLK			GPIO_GP_3_24
#define SSTBZ			GPIO_GP_3_25
#define MOSI			GPIO_GP_3_26
#define MISO			GPIO_GP_3_27

#define CPLD_ADDR_MODE		0x00 /* RW */
#define CPLD_ADDR_MUX		0x01 /* RW */
#define CPLD_ADDR_HDMI		0x02 /* RW */
#define CPLD_ADDR_DIPSW		0x08 /* R */
#define CPLD_ADDR_RESET		0x80 /* RW */
#define CPLD_ADDR_VERSION	0xFF /* R */

static u32 cpld_read(u8 addr)
{
	int i;
	u32 data = 0;

	for (i = 0; i < 8; i++) {
		gpio_set_value(MOSI, addr & 0x80); /* MSB first */
		gpio_set_value(SCLK, 1);
		addr <<= 1;
		gpio_set_value(SCLK, 0);
	}

	gpio_set_value(MOSI, 0); /* READ */
	gpio_set_value(SSTBZ, 0);
	gpio_set_value(SCLK, 1);
	gpio_set_value(SCLK, 0);
	gpio_set_value(SSTBZ, 1);

	for (i = 0; i < 32; i++) {
		gpio_set_value(SCLK, 1);
		data <<= 1;
		data |= gpio_get_value(MISO); /* MSB first */
		gpio_set_value(SCLK, 0);
	}

	return data;
}

static void cpld_write(u8 addr, u32 data)
{
	int i;

	for (i = 0; i < 32; i++) {
		gpio_set_value(MOSI, data & (1 << 31)); /* MSB first */
		gpio_set_value(SCLK, 1);
		data <<= 1;
		gpio_set_value(SCLK, 0);
	}

	for (i = 0; i < 8; i++) {
		gpio_set_value(MOSI, addr & 0x80); /* MSB first */
		gpio_set_value(SCLK, 1);
		addr <<= 1;
		gpio_set_value(SCLK, 0);
	}

	gpio_set_value(MOSI, 1); /* WRITE */
	gpio_set_value(SSTBZ, 0);
	gpio_set_value(SCLK, 1);
	gpio_set_value(SCLK, 0);
	gpio_set_value(SSTBZ, 1);
}

/* LSI pin pull-up control */
#define PUPR3		0xe606010C
#define PUPR3_SD3_DAT1	(1 << 27)

void cpld_init(void)
{
	u32 val;

	/* PULL-UP on MISO line */
	val = readl(PUPR3);
	val |= PUPR3_SD3_DAT1;
	writel(val, PUPR3);

	gpio_request(SCLK, NULL);
	gpio_request(SSTBZ, NULL);
	gpio_request(MOSI, NULL);
	gpio_request(MISO, NULL);

	gpio_direction_output(SCLK, 0);
	gpio_direction_output(SSTBZ, 1);
	gpio_direction_output(MOSI, 0);
	gpio_direction_input(MISO);

	/* dummy read */
	cpld_read(CPLD_ADDR_VERSION);

	printf("CPLD version:              0x%08x\n",
	       cpld_read(CPLD_ADDR_VERSION));
	printf("H2 Mode setting (MD0..28): 0x%08x\n",
	       cpld_read(CPLD_ADDR_MODE));
	printf("Multiplexer settings:      0x%08x\n",
	       cpld_read(CPLD_ADDR_MUX));
	printf("HDMI setting:              0x%08x\n",
	       cpld_read(CPLD_ADDR_HDMI));
	printf("DIPSW (SW3):               0x%08x\n",
	       cpld_read(CPLD_ADDR_DIPSW));

#ifdef CONFIG_SH_SDHI
	/* switch MUX to SD0 */
	val = cpld_read(CPLD_ADDR_MUX);
	val &= ~MUX_MSK_SD0;
	val |= MUX_VAL_SD0;
	cpld_write(CPLD_ADDR_MUX, val);
#endif
}

static int do_cpld(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	u32 addr, val;

	if (argc < 3)
		return CMD_RET_USAGE;

	addr = simple_strtoul(argv[2], NULL, 16);
	if (!(addr == CPLD_ADDR_VERSION || addr == CPLD_ADDR_MODE ||
	      addr == CPLD_ADDR_MUX || addr == CPLD_ADDR_HDMI ||
	      addr == CPLD_ADDR_DIPSW || addr == CPLD_ADDR_RESET)) {
		printf("cpld invalid addr\n");
		return CMD_RET_USAGE;
	}

	if (argc == 3 && strcmp(argv[1], "read") == 0) {
		printf("0x%x\n", cpld_read(addr));
	} else if (argc == 4 && strcmp(argv[1], "write") == 0) {
		val = simple_strtoul(argv[3], NULL, 16);
		if (addr == CPLD_ADDR_MUX) {
			/* never mask SCIFA0 console */
			val &= ~MUX_MSK_SCIFA0_USB;
			val |= MUX_VAL_SCIFA0_USB;
		}
		cpld_write(addr, val);
	}

	return 0;
}

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

void reset_cpu(ulong addr)
{
	cpld_write(CPLD_ADDR_RESET, 1);
}