1 /*
2 * Copyright (c) 2026, Renesas Electronics Corporation. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8 #include <string.h>
9
10 #include <common/debug.h>
11 #include <drivers/spi_nor.h>
12 #include <lib/mmio.h>
13
14 #include "rpc.h"
15 #include "rpc_registers.h"
16
rpc_get_drenr(const struct spi_mem_op * op)17 static uint32_t rpc_get_drenr(const struct spi_mem_op *op)
18 {
19 /* Command output enabled, optional command output disabled */
20 uint32_t drenr = RPC_DRENR_CDE;
21
22 /* Address enable */
23 switch (op->addr.nbytes) {
24 case 3:
25 drenr |= RPC_DRENR_ADE_3BYTE << RPC_DRENR_ADE_POS;
26 break;
27 case 4:
28 drenr |= RPC_DRENR_ADE_4BYTE << RPC_DRENR_ADE_POS;
29 break;
30 default:
31 drenr |= RPC_DRENR_ADE_NONE << RPC_DRENR_ADE_POS;
32 break;
33 }
34
35 /* Set bit size of following fields:
36 * Command, optional command, address, option data, data
37 */
38 if ((op->cmd.buswidth == SPI_MEM_BUSWIDTH_1_LINE) &&
39 (op->addr.buswidth == SPI_MEM_BUSWIDTH_1_LINE) &&
40 (op->data.buswidth == SPI_MEM_BUSWIDTH_1_LINE)) {
41 drenr |= RPC_DRENR_DB_1BIT << RPC_DRENR_CDB_POS |
42 RPC_DRENR_DB_1BIT << RPC_DRENR_OCDB_POS |
43 RPC_DRENR_DB_1BIT << RPC_DRENR_ADB_POS |
44 RPC_DRENR_DB_1BIT << RPC_DRENR_OPDB_POS |
45 RPC_DRENR_DB_1BIT << RPC_DRENR_DRDB_POS;
46 } else if ((op->cmd.buswidth == SPI_MEM_BUSWIDTH_1_LINE) &&
47 (op->addr.buswidth == SPI_MEM_BUSWIDTH_1_LINE) &&
48 (op->data.buswidth == SPI_MEM_BUSWIDTH_4_LINE)) {
49 drenr |= RPC_DRENR_DB_1BIT << RPC_DRENR_CDB_POS |
50 RPC_DRENR_DB_1BIT << RPC_DRENR_OCDB_POS |
51 RPC_DRENR_DB_1BIT << RPC_DRENR_ADB_POS |
52 RPC_DRENR_DB_1BIT << RPC_DRENR_OPDB_POS |
53 RPC_DRENR_DB_4BIT << RPC_DRENR_DRDB_POS;
54 } else if ((op->cmd.buswidth == SPI_MEM_BUSWIDTH_1_LINE) &&
55 (op->addr.buswidth == SPI_MEM_BUSWIDTH_4_LINE) &&
56 (op->data.buswidth == SPI_MEM_BUSWIDTH_4_LINE)) {
57 drenr |= RPC_DRENR_DB_1BIT << RPC_DRENR_CDB_POS |
58 RPC_DRENR_DB_1BIT << RPC_DRENR_OCDB_POS |
59 RPC_DRENR_DB_4BIT << RPC_DRENR_ADB_POS |
60 RPC_DRENR_DB_4BIT << RPC_DRENR_OPDB_POS |
61 RPC_DRENR_DB_4BIT << RPC_DRENR_DRDB_POS;
62 }
63
64 /* Dummy cycle enable */
65 drenr |= RPC_DRENR_DME;
66
67 /* Optional data enable */
68 drenr |= RPC_DRENR_OPDE_1BYTE << RPC_DRENR_OPDE_POS;
69
70 return drenr;
71 }
72
rpc_config_xread_mode(const struct spi_mem_op * op)73 int rpc_config_xread_mode(const struct spi_mem_op *op)
74 {
75 if (op->data.dir != SPI_MEM_DATA_IN) {
76 ERROR("%s: only read command is supported for external read mode\n",
77 __func__);
78 return -1;
79 }
80
81 if ((op->cmd.buswidth != SPI_MEM_BUSWIDTH_1_LINE) ||
82 (op->addr.buswidth != SPI_MEM_BUSWIDTH_4_LINE) ||
83 (op->data.buswidth != SPI_MEM_BUSWIDTH_4_LINE)) {
84 ERROR("%s: currently, only 1-4-4 format is supported\n",
85 __func__);
86 return -1;
87 }
88
89 /* Switch to manual mode to temporarily disable external address space read mode */
90 mmio_clrsetbits_32(RPC_CMNCR, RPC_CMNCR_MD, 1u << RPC_CMNCR_MD_POS);
91
92 uint32_t mask = 0;
93 uint32_t set = 0;
94
95 /* PHYOFFSET1 */
96 mask = RPC_PHYOFFSET1_DDRTMG;
97 set = RPC_PHYOFFSET1_SDR << RPC_PHYOFFSET1_DDRTMG_POS;
98 mmio_clrsetbits_32(RPC_PHYOFFSET1, mask, set);
99
100 /* PHYOFFSET2 */
101 mask = RPC_PHYOFFSET2_OCTTMG;
102 set = RPC_PHYOFFSET2_SPI << RPC_PHYOFFSET2_OCTTMG_POS;
103 mmio_clrsetbits_32(RPC_PHYOFFSET2, mask, set);
104
105 /* PHYCNT */
106 mask = RPC_PHYCNT_PHYMEM;
107 set = (RPC_PHYCNT_SDR << RPC_PHYCNT_PHYMEM_POS) | RPC_PHYCNT_CAL;
108 mmio_clrsetbits_32(RPC_PHYCNT, mask, set);
109
110 /* CMNCR */
111 mask = RPC_CMNCR_BSZ | RPC_CMNCR_IO2FV | RPC_CMNCR_IO3FV |
112 RPC_CMNCR_MOIIO1 | RPC_CMNCR_MOIIO2 | RPC_CMNCR_MOIIO3;
113 set = (RPC_CMNCR_BSZ_SINGLE << RPC_CMNCR_BSZ_POS) |
114 (RPC_CMNCR_IO_HIGH << RPC_CMNCR_MOIIO3_POS) |
115 (RPC_CMNCR_IO_KEEP << RPC_CMNCR_IO3FV_POS) |
116 (RPC_CMNCR_IO_HIZ << RPC_CMNCR_MOIIO2_POS) |
117 (RPC_CMNCR_IO_HIZ << RPC_CMNCR_IO2FV_POS) |
118 (RPC_CMNCR_IO_HIZ << RPC_CMNCR_MOIIO1_POS);
119 mmio_clrsetbits_32(RPC_CMNCR, mask, set);
120
121 /* SSLDR */
122 mask = RPC_SSLDR_SCKDL | RPC_SSLDR_SLNDL | RPC_SSLDR_SPNDL;
123 set = (0 << RPC_SSLDR_SCKDL_POS) | (0 << RPC_SSLDR_SLNDL_POS) |
124 (6u << RPC_SSLDR_SPNDL_POS);
125 mmio_clrsetbits_32(RPC_SSLDR, mask, set);
126
127 /* DRCR */
128 mask = RPC_DRCR_RBURST | RPC_DRCR_RBE | RPC_DRCR_SSLE;
129 set = (7u << RPC_DRCR_RBURST_POS) | RPC_DRCR_RCF | RPC_DRCR_RBE | RPC_DRCR_SSLE;
130 mmio_clrsetbits_32(RPC_DRCR, mask, set);
131
132 /* DRCMR */
133 mask = RPC_DRCMR_CMD | RPC_DRCMR_OCMD;
134 set = (op->cmd.opcode & 0xff) << RPC_DRCMR_CMD_POS;
135 mmio_clrsetbits_32(RPC_DRCMR, mask, set);
136
137 /* DROPR */
138 mask = 0xffff;
139 set = (0x55555555u & 0xffu) << RPC_DROPR_OPD3_POS;
140 mmio_write_32(RPC_DROPR, set);
141
142 /* DRENR */
143 mask = RPC_DRENR_ADB | RPC_DRENR_ADE | RPC_DRENR_CDB | RPC_DRENR_CDE |
144 RPC_DRENR_DME | RPC_DRENR_DRDB | RPC_DRENR_OCDB |
145 RPC_DRENR_OCDE | RPC_DRENR_OPDB | RPC_DRENR_OPDE;
146 set = rpc_get_drenr(op);
147 mmio_clrsetbits_32(RPC_DRENR, mask, set);
148
149 /* DRDMCR */
150 mask = RPC_DRDMCR_DMCYC;
151 set = (op->dummy.nbytes * 2 - 1) << RPC_DRDMCR_DMCYC_POS;
152 mmio_write_32(RPC_DRDMCR, set);
153
154 /* DRDRENR */
155 mask = RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE | RPC_DRDRENR_HYPE | RPC_DRDRENR_OPDRE;
156 set = 0;
157 mmio_clrsetbits_32(RPC_DRDRENR, mask, set);
158
159 /* Start XIP */
160 mmio_clrbits_32(RPC_CMNCR, RPC_CMNCR_MD);
161 mmio_read_32(RPC_CMNCR);
162
163 return 0;
164 }
165