1*21871138SVladimir Barinov /*
2*21871138SVladimir Barinov * Stout board CPLD access support
3*21871138SVladimir Barinov *
4*21871138SVladimir Barinov * Copyright (C) 2015 Renesas Electronics Europe GmbH
5*21871138SVladimir Barinov * Copyright (C) 2015 Renesas Electronics Corporation
6*21871138SVladimir Barinov * Copyright (C) 2015 Cogent Embedded, Inc.
7*21871138SVladimir Barinov *
8*21871138SVladimir Barinov * SPDX-License-Identifier: GPL-2.0
9*21871138SVladimir Barinov */
10*21871138SVladimir Barinov
11*21871138SVladimir Barinov #include <common.h>
12*21871138SVladimir Barinov #include <asm/io.h>
13*21871138SVladimir Barinov #include <asm/gpio.h>
14*21871138SVladimir Barinov #include "cpld.h"
15*21871138SVladimir Barinov
16*21871138SVladimir Barinov #define SCLK GPIO_GP_3_24
17*21871138SVladimir Barinov #define SSTBZ GPIO_GP_3_25
18*21871138SVladimir Barinov #define MOSI GPIO_GP_3_26
19*21871138SVladimir Barinov #define MISO GPIO_GP_3_27
20*21871138SVladimir Barinov
21*21871138SVladimir Barinov #define CPLD_ADDR_MODE 0x00 /* RW */
22*21871138SVladimir Barinov #define CPLD_ADDR_MUX 0x01 /* RW */
23*21871138SVladimir Barinov #define CPLD_ADDR_HDMI 0x02 /* RW */
24*21871138SVladimir Barinov #define CPLD_ADDR_DIPSW 0x08 /* R */
25*21871138SVladimir Barinov #define CPLD_ADDR_RESET 0x80 /* RW */
26*21871138SVladimir Barinov #define CPLD_ADDR_VERSION 0xFF /* R */
27*21871138SVladimir Barinov
cpld_read(u8 addr)28*21871138SVladimir Barinov static u32 cpld_read(u8 addr)
29*21871138SVladimir Barinov {
30*21871138SVladimir Barinov int i;
31*21871138SVladimir Barinov u32 data = 0;
32*21871138SVladimir Barinov
33*21871138SVladimir Barinov for (i = 0; i < 8; i++) {
34*21871138SVladimir Barinov gpio_set_value(MOSI, addr & 0x80); /* MSB first */
35*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
36*21871138SVladimir Barinov addr <<= 1;
37*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
38*21871138SVladimir Barinov }
39*21871138SVladimir Barinov
40*21871138SVladimir Barinov gpio_set_value(MOSI, 0); /* READ */
41*21871138SVladimir Barinov gpio_set_value(SSTBZ, 0);
42*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
43*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
44*21871138SVladimir Barinov gpio_set_value(SSTBZ, 1);
45*21871138SVladimir Barinov
46*21871138SVladimir Barinov for (i = 0; i < 32; i++) {
47*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
48*21871138SVladimir Barinov data <<= 1;
49*21871138SVladimir Barinov data |= gpio_get_value(MISO); /* MSB first */
50*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
51*21871138SVladimir Barinov }
52*21871138SVladimir Barinov
53*21871138SVladimir Barinov return data;
54*21871138SVladimir Barinov }
55*21871138SVladimir Barinov
cpld_write(u8 addr,u32 data)56*21871138SVladimir Barinov static void cpld_write(u8 addr, u32 data)
57*21871138SVladimir Barinov {
58*21871138SVladimir Barinov int i;
59*21871138SVladimir Barinov
60*21871138SVladimir Barinov for (i = 0; i < 32; i++) {
61*21871138SVladimir Barinov gpio_set_value(MOSI, data & (1 << 31)); /* MSB first */
62*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
63*21871138SVladimir Barinov data <<= 1;
64*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
65*21871138SVladimir Barinov }
66*21871138SVladimir Barinov
67*21871138SVladimir Barinov for (i = 0; i < 8; i++) {
68*21871138SVladimir Barinov gpio_set_value(MOSI, addr & 0x80); /* MSB first */
69*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
70*21871138SVladimir Barinov addr <<= 1;
71*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
72*21871138SVladimir Barinov }
73*21871138SVladimir Barinov
74*21871138SVladimir Barinov gpio_set_value(MOSI, 1); /* WRITE */
75*21871138SVladimir Barinov gpio_set_value(SSTBZ, 0);
76*21871138SVladimir Barinov gpio_set_value(SCLK, 1);
77*21871138SVladimir Barinov gpio_set_value(SCLK, 0);
78*21871138SVladimir Barinov gpio_set_value(SSTBZ, 1);
79*21871138SVladimir Barinov }
80*21871138SVladimir Barinov
81*21871138SVladimir Barinov /* LSI pin pull-up control */
82*21871138SVladimir Barinov #define PUPR3 0xe606010C
83*21871138SVladimir Barinov #define PUPR3_SD3_DAT1 (1 << 27)
84*21871138SVladimir Barinov
cpld_init(void)85*21871138SVladimir Barinov void cpld_init(void)
86*21871138SVladimir Barinov {
87*21871138SVladimir Barinov u32 val;
88*21871138SVladimir Barinov
89*21871138SVladimir Barinov /* PULL-UP on MISO line */
90*21871138SVladimir Barinov val = readl(PUPR3);
91*21871138SVladimir Barinov val |= PUPR3_SD3_DAT1;
92*21871138SVladimir Barinov writel(val, PUPR3);
93*21871138SVladimir Barinov
94*21871138SVladimir Barinov gpio_request(SCLK, NULL);
95*21871138SVladimir Barinov gpio_request(SSTBZ, NULL);
96*21871138SVladimir Barinov gpio_request(MOSI, NULL);
97*21871138SVladimir Barinov gpio_request(MISO, NULL);
98*21871138SVladimir Barinov
99*21871138SVladimir Barinov gpio_direction_output(SCLK, 0);
100*21871138SVladimir Barinov gpio_direction_output(SSTBZ, 1);
101*21871138SVladimir Barinov gpio_direction_output(MOSI, 0);
102*21871138SVladimir Barinov gpio_direction_input(MISO);
103*21871138SVladimir Barinov
104*21871138SVladimir Barinov /* dummy read */
105*21871138SVladimir Barinov cpld_read(CPLD_ADDR_VERSION);
106*21871138SVladimir Barinov
107*21871138SVladimir Barinov printf("CPLD version: 0x%08x\n",
108*21871138SVladimir Barinov cpld_read(CPLD_ADDR_VERSION));
109*21871138SVladimir Barinov printf("H2 Mode setting (MD0..28): 0x%08x\n",
110*21871138SVladimir Barinov cpld_read(CPLD_ADDR_MODE));
111*21871138SVladimir Barinov printf("Multiplexer settings: 0x%08x\n",
112*21871138SVladimir Barinov cpld_read(CPLD_ADDR_MUX));
113*21871138SVladimir Barinov printf("HDMI setting: 0x%08x\n",
114*21871138SVladimir Barinov cpld_read(CPLD_ADDR_HDMI));
115*21871138SVladimir Barinov printf("DIPSW (SW3): 0x%08x\n",
116*21871138SVladimir Barinov cpld_read(CPLD_ADDR_DIPSW));
117*21871138SVladimir Barinov
118*21871138SVladimir Barinov #ifdef CONFIG_SH_SDHI
119*21871138SVladimir Barinov /* switch MUX to SD0 */
120*21871138SVladimir Barinov val = cpld_read(CPLD_ADDR_MUX);
121*21871138SVladimir Barinov val &= ~MUX_MSK_SD0;
122*21871138SVladimir Barinov val |= MUX_VAL_SD0;
123*21871138SVladimir Barinov cpld_write(CPLD_ADDR_MUX, val);
124*21871138SVladimir Barinov #endif
125*21871138SVladimir Barinov }
126*21871138SVladimir Barinov
do_cpld(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])127*21871138SVladimir Barinov static int do_cpld(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
128*21871138SVladimir Barinov {
129*21871138SVladimir Barinov u32 addr, val;
130*21871138SVladimir Barinov
131*21871138SVladimir Barinov if (argc < 3)
132*21871138SVladimir Barinov return CMD_RET_USAGE;
133*21871138SVladimir Barinov
134*21871138SVladimir Barinov addr = simple_strtoul(argv[2], NULL, 16);
135*21871138SVladimir Barinov if (!(addr == CPLD_ADDR_VERSION || addr == CPLD_ADDR_MODE ||
136*21871138SVladimir Barinov addr == CPLD_ADDR_MUX || addr == CPLD_ADDR_HDMI ||
137*21871138SVladimir Barinov addr == CPLD_ADDR_DIPSW || addr == CPLD_ADDR_RESET)) {
138*21871138SVladimir Barinov printf("cpld invalid addr\n");
139*21871138SVladimir Barinov return CMD_RET_USAGE;
140*21871138SVladimir Barinov }
141*21871138SVladimir Barinov
142*21871138SVladimir Barinov if (argc == 3 && strcmp(argv[1], "read") == 0) {
143*21871138SVladimir Barinov printf("0x%x\n", cpld_read(addr));
144*21871138SVladimir Barinov } else if (argc == 4 && strcmp(argv[1], "write") == 0) {
145*21871138SVladimir Barinov val = simple_strtoul(argv[3], NULL, 16);
146*21871138SVladimir Barinov if (addr == CPLD_ADDR_MUX) {
147*21871138SVladimir Barinov /* never mask SCIFA0 console */
148*21871138SVladimir Barinov val &= ~MUX_MSK_SCIFA0_USB;
149*21871138SVladimir Barinov val |= MUX_VAL_SCIFA0_USB;
150*21871138SVladimir Barinov }
151*21871138SVladimir Barinov cpld_write(addr, val);
152*21871138SVladimir Barinov }
153*21871138SVladimir Barinov
154*21871138SVladimir Barinov return 0;
155*21871138SVladimir Barinov }
156*21871138SVladimir Barinov
157*21871138SVladimir Barinov U_BOOT_CMD(
158*21871138SVladimir Barinov cpld, 4, 1, do_cpld,
159*21871138SVladimir Barinov "CPLD access",
160*21871138SVladimir Barinov "read addr\n"
161*21871138SVladimir Barinov "cpld write addr val\n"
162*21871138SVladimir Barinov );
163*21871138SVladimir Barinov
reset_cpu(ulong addr)164*21871138SVladimir Barinov void reset_cpu(ulong addr)
165*21871138SVladimir Barinov {
166*21871138SVladimir Barinov cpld_write(CPLD_ADDR_RESET, 1);
167*21871138SVladimir Barinov }
168