ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_usb_dev.c
Go to the documentation of this file.
1
14
15#include <stdio.h>
16#include <string.h>
17
18#include "board_usb_internal.h"
19#include "ra8_elc_regs.h"
20#include "ra8_usb_regs.h"
21
23uint16_t priv_usb_intsts0(void)
24{
25 uint16_t v = s_usb.reg[internal_usb_word((uint64_t)k_ra8_usb_off_intsts0)];
26 v &= (uint16_t)((1U << k_ra8_int0_bit_brdy) | (1U << k_ra8_int0_bit_nrdy) |
29 v = (uint16_t)(v | (s_usb.ctsq & (uint16_t)k_ra8_intsts0_mask_ctsq));
30 v = (uint16_t)(v | (s_usb.dvsq & (uint16_t)k_ra8_intsts0_mask_dvsq));
31 v = (uint16_t)(v | (uint16_t)k_ra8_intsts0_mask_vbsts); /* VBUS always present. */
32 if (s_usb.setup_valid) {
33 v = (uint16_t)(v | (uint16_t)k_ra8_intsts0_mask_valid);
34 }
35 return v;
36}
37
39void priv_usb_intsts0_set(uint8_t bit)
40{
41 const uint32_t w = internal_usb_word((uint64_t)k_ra8_usb_off_intsts0);
42 s_usb.reg[w] = (uint16_t)(s_usb.reg[w] | (uint16_t)(1U << bit));
43}
44
46void priv_usb_raise_irq(uc_engine* uc)
47{
48 if (s_raise != nullptr) {
50 s_usb_irqs++;
51 }
52}
53
54/* =============================================================================
55 * CFIFO routing -- map CFIFOSEL (CURPIPE + ISEL) to the active staging buffer.
56 * =============================================================================
57 */
58
70{
71 const uint16_t sel = s_usb.reg[internal_usb_word((uint64_t)k_ra8_usb_off_cfifosel)];
72 return (uint8_t)(sel & (uint16_t)k_ra8_fifosel_curpipe);
73}
74
86{
87 const uint16_t sel = s_usb.reg[internal_usb_word((uint64_t)k_ra8_usb_off_cfifosel)];
88 return (sel & (uint16_t)k_ra8_fifosel_isel) != 0U;
89}
90
93{
94 const uint8_t p = internal_cfifo_pipe();
95 return (p == 0U) ? &s_usb.dcp_in : &s_usb.pipe_in[p % k_usb_pipe_count];
96}
97
100{
101 const uint8_t p = internal_cfifo_pipe();
102 return (p == 0U) ? &s_usb.dcp_out : &s_usb.pipe_out[p % k_usb_pipe_count];
103}
104
116{
117 if (internal_cfifo_is_in()) {
118 return 0U;
119 }
121 return (uint16_t)(b->len - b->rd);
122}
123
135RA8_INTERNAL static uint32_t internal_cfifo_read_port(unsigned size)
136{
138 uint32_t v = 0U;
139 for (unsigned i = 0U; (i < size) && (b->rd < b->len); i++) {
140 v |= (uint32_t)((uint32_t)b->data[b->rd] << (i * k_usb_byte_bits));
141 b->rd++;
142 }
143 return v;
144}
145
156RA8_INTERNAL static void internal_cfifo_write_port(uint32_t value, unsigned size)
157{
159 for (unsigned i = 0U; (i < size) && (b->len < (uint16_t)sizeof(b->data)); i++) {
160 b->data[b->len] = (uint8_t)((value >> (i * k_usb_byte_bits)) & k_usb_byte_mask);
161 b->len++;
162 }
163}
164
174RA8_INTERNAL static void internal_cfifoctr_write(uint16_t value)
175{
176 if ((value & (uint16_t)k_ra8_fifoctr_bclr) != 0U) {
177 if (internal_cfifo_is_in()) {
179 b->len = 0U;
180 b->valid = false;
181 } else {
183 b->rd = b->len; /* drop the remainder of the OUT buffer. */
184 }
185 }
186 if ((value & (uint16_t)k_ra8_fifoctr_bval) != 0U) {
187 if (internal_cfifo_is_in()) {
188 internal_cfifo_in_buf()->valid = true; /* IN buffer committed; ready for the host. */
189 }
190 }
191}
192
193/* =============================================================================
194 * Register read / write dispatch (USBFS window at 0x40250000).
195 * =============================================================================
196 */
197
209{
210 return (uint16_t)((uint16_t)k_ra8_fifoctr_frdy |
212}
213
215uint32_t priv_usb_reg_read(uint64_t off, unsigned size)
216{
217 switch ((uint16_t)off) {
218 case (uint16_t)k_ra8_usb_off_intsts0:
219 return priv_usb_intsts0();
220 case (uint16_t)k_ra8_usb_off_cfifoctr:
221 return internal_cfifoctr_read();
222 case (uint16_t)k_ra8_usb_off_cfifo:
223 case (uint16_t)((uint16_t)k_ra8_usb_off_cfifo + (uint16_t)k_usb_cfifo_h): /* CFIFOH tail. */
224 case (uint16_t)((uint16_t)k_ra8_usb_off_cfifo + (uint16_t)k_usb_cfifo_hh): /* CFIFOHH tail. */
225 /* Full access width: the HS instance drains its CFIFO 32 bits at a time
226 * (MBW=32) with 16/8-bit residual reads through the CFIFOH / CFIFOHH
227 * aliases (HUM Ch 37.2.7 "CFIFO, DnFIFO : FIFO Port Register" p 2069-2070); the FS
228 * instance uses 16-bit accesses at the base port. */
229 return internal_cfifo_read_port(size);
230 case (uint16_t)k_ra8_usb_off_syssts0:
231 return (uint16_t)0x0003U; /* LNST = J-state: device pull-up seen. */
232 case (uint16_t)k_ra8_usb_off_dvstctr0: {
233 /* HUM Ch 36.2.5 "DVSTCTR0 : Device State Control Register 0", p 1971:
234 * RHST[2:0] reports the settled link speed once the host's bus reset
235 * completes; the device firmware (internal_dvst_track_speed in the DCD)
236 * re-aims the USBX framework at it. The modelled loop is a full-speed
237 * link (the FS controller's ceiling caps it in either polarity), so
238 * report FS from the moment the device has left Powered. */
239 uint16_t v = s_usb.reg[internal_usb_word(off)];
240 if (s_usb.dvsq != (uint16_t)k_ra8_dvsq_powered) {
241 v = (uint16_t)(v | (uint16_t)k_usb_rhst_fs);
242 }
243 return v;
244 }
245 case (uint16_t)k_ra8_usb_off_frmnum:
246 return s_usb.reg[internal_usb_word((uint64_t)k_ra8_usb_off_frmnum)];
247 default:
248 return s_usb.reg[internal_usb_word(off)];
249 }
250}
251
253void priv_usb_reg_write(uint64_t off, uint32_t value, unsigned size)
254{
255 const uint16_t v16 = (uint16_t)value;
256 switch ((uint16_t)off) {
257 case (uint16_t)k_ra8_usb_off_cfifo:
258 case (uint16_t)((uint16_t)k_ra8_usb_off_cfifo + (uint16_t)k_usb_cfifo_h): /* CFIFOH tail. */
259 case (uint16_t)((uint16_t)k_ra8_usb_off_cfifo + (uint16_t)k_usb_cfifo_hh): /* CFIFOHH tail. */
260 /* Full access width: the HS instance fills its CFIFO 32 bits at a time
261 * (MBW=32) with 16/8-bit residual writes through the CFIFOH / CFIFOHH
262 * aliases (HUM Ch 37.2.7 "CFIFO, DnFIFO : FIFO Port Register" p 2069-2070); truncating to
263 * 16 bits here zeroed bytes 2-3 of every descriptor word in Config B. */
264 internal_cfifo_write_port(value, size);
265 return;
266 case (uint16_t)k_ra8_usb_off_cfifoctr:
268 return;
269 case (uint16_t)k_ra8_usb_off_intsts0:
270 /* W0C on the event bits: a written 0 clears, a 1 preserves. */
271 s_usb.reg[internal_usb_word(off)] &= v16;
272 if ((v16 & (uint16_t)k_ra8_intsts0_mask_valid) == 0U) {
273 s_usb.setup_valid = false;
274 }
275 return;
276 default:
277 s_usb.reg[internal_usb_word(off)] = v16;
278 return;
279 }
280}
281
282uint64_t board_usb_read(uc_engine* uc, uint64_t addr, unsigned size, bool* handled)
283{
284 (void)uc;
285 if ((addr < (uint64_t)k_usb_base) || (addr >= ((uint64_t)k_usb_base + (uint64_t)k_usb_span))) {
286 *handled = false;
287 return 0U;
288 }
289 *handled = true;
290 if (s_roles_swapped) {
291 /* Config B: the polled ra8_usb_host_* driver owns the USBFS controller. */
292 return board_usbhs_host_reg_read(uc, addr - (uint64_t)k_usb_base, size);
293 }
294 return (uint64_t)priv_usb_reg_read(addr - (uint64_t)k_usb_base, size);
295}
296
297void board_usb_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value, bool* handled)
298{
299 if ((addr < (uint64_t)k_usb_base) || (addr >= ((uint64_t)k_usb_base + (uint64_t)k_usb_span))) {
300 *handled = false;
301 return;
302 }
303 *handled = true;
304 const uint64_t off = addr - (uint64_t)k_usb_base;
305 /* Role declaration (HUM Ch 36.2.1 SYSCFG.DCFM, p 1966): the firmware writes
306 * DCFM=1 to select controller (host) function on THIS instance. Under the
307 * self-loop bridge that pins the FS window to the host model -- Config B. */
308 if (s_external_host && !s_roles_swapped && (off == (uint64_t)k_ra8_usb_off_syscfg) &&
309 (((uint16_t)value & (uint16_t)(1U << k_ra8_syscfg_bit_dcfm)) != 0U)) {
311 }
312 if (s_roles_swapped) {
313 board_usbhs_host_reg_write(uc, off, size, value);
314 return;
315 }
316 priv_usb_reg_write(off, (uint32_t)value, size);
317}
void board_usbhs_host_reg_write(uc_engine *uc, uint64_t off, unsigned size, uint64_t value)
Host-model register write by window byte offset (role routing).
uint64_t board_usbhs_host_reg_read(uc_engine *uc, uint64_t off, unsigned size)
Host-model register read by window byte offset (role routing).
void board_usb_roles_swap(uc_engine *uc)
Swap the self-loop window<->model bindings (enter Config B).
void priv_usb_reg_write(uint64_t off, uint32_t value, unsigned size)
Write one device-controller register; off is the byte offset into the window.
static uint8_t internal_cfifo_pipe(void)
Currently-selected CFIFO pipe number (CFIFOSEL.CURPIPE[3:0]).
void priv_usb_raise_irq(uc_engine *uc)
Raise the device controller interrupt (USBFS_INT, or USBHS after a role swap).
static usb_out_buf_t * internal_cfifo_out_buf(void)
The device-OUT staging buffer CFIFOSEL currently points at.
void board_usb_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value, bool *handled)
Dispatch an MMIO write inside the USBFS register window.
static uint32_t internal_cfifo_read_port(unsigned size)
Service a CFIFO data-port read: drain one unit (1..4 bytes) from the OUT buffer.
uint16_t priv_usb_intsts0(void)
INTSTS0 value the device reads: event bits OR computed fields.
static uint16_t internal_cfifoctr_read(void)
CFIFOCTR read value: FRDY always ready, DTLN = OUT bytes available.
static void internal_cfifo_write_port(uint32_t value, unsigned size)
Service a CFIFO data-port write: append one unit (1..4 bytes) to the IN buffer.
void priv_usb_intsts0_set(uint8_t bit)
Set an INTSTS0 event bit in the shadow (host asserts it).
static usb_in_buf_t * internal_cfifo_in_buf(void)
The device-IN staging buffer CFIFOSEL currently points at.
static bool internal_cfifo_is_in(void)
True when CFIFOSEL selects the IN direction (device writes / fills).
static uint16_t internal_cfifo_dtln(void)
Bytes still available for the device to read on the selected OUT buf.
uint64_t board_usb_read(uc_engine *uc, uint64_t addr, unsigned size, bool *handled)
Dispatch an MMIO read inside the USBFS register window.
static void internal_cfifoctr_write(uint16_t value)
Apply a CFIFOCTR write: BCLR clears the buffer, BVAL commits an IN.
uint32_t priv_usb_reg_read(uint64_t off, unsigned size)
Read one device-controller register; off is the byte offset into the window.
Module-private state + interfaces shared by the board_usb TUs.
bool s_external_host
Bridge host owns the bus (core).
Definition board_usb.c:41
usb_state_t s_usb
Controller + FIFO state (core).
Definition board_usb.c:33
@ k_usb_rhst_fs
Link settled at full speed after the bus reset.
@ k_usb_base
USBFS base (HUM Ch 36, p 1965).
@ k_usb_span
Modelled window (PIPECTR end < 0x90).
@ k_usb_pipe_count
DCP (0) + PIPE1..PIPE9.
uint32_t s_usb_irqs
USB interrupts raised (core).
Definition board_usb.c:73
@ k_usb_cfifo_hh
CFIFOHH alias offset from CFIFO (+0x3).
@ k_usb_cfifo_h
CFIFOH alias offset from CFIFO (+0x2).
@ k_usb_byte_mask
One-byte mask.
@ k_usb_byte_bits
Bits per byte.
static uint32_t internal_usb_word(uint64_t off)
Word index into the 16-bit register shadow for a window offset.
bool s_roles_swapped
Self-loop role polarity (core).
Definition board_usb.c:49
uint16_t g_dev_irq_event
Device ICU event number (core).
Definition board_usb.c:54
board_usb_irq_raiser_t s_raise
ICU pend callback (core).
Definition board_usb.c:35
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Event Link Controller (ELC) register layout for the Renesas RA8D2.
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
@ k_ra8_syscfg_bit_dcfm
1 = host mode, 0 = device.
@ k_ra8_usb_off_syssts0
SYSSTS0 : System status 0.
@ k_ra8_usb_off_dvstctr0
DVSTCTR0 : Device state ctrl.
@ k_ra8_usb_off_cfifosel
CFIFOSEL : Control FIFO select.
@ k_ra8_usb_off_cfifo
CFIFO : Control FIFO port.
@ k_ra8_usb_off_intsts0
INTSTS0 : Interrupt Status 0.
@ k_ra8_usb_off_cfifoctr
CFIFOCTR : Control FIFO control.
@ k_ra8_usb_off_syscfg
SYSCFG : System config.
@ k_ra8_usb_off_frmnum
FRMNUM : Frame number.
@ k_ra8_fifoctr_frdy
FIFO ready.
@ k_ra8_fifoctr_bclr
Buffer clear.
@ k_ra8_fifoctr_dtln
Data length (write-bytes-rem).
@ k_ra8_fifoctr_bval
Buffer valid.
@ k_ra8_fifosel_isel
CFIFO direction (DCP only).
@ k_ra8_fifosel_curpipe
Current pipe select [3:0].
@ k_ra8_intsts0_mask_dvsq
Device state.
@ k_ra8_intsts0_mask_valid
SETUP packet detect flag.
@ k_ra8_intsts0_mask_vbsts
VBUS input port level.
@ k_ra8_intsts0_mask_ctsq
Control transfer stage.
@ k_ra8_int0_bit_bemp
Buffer-empty interrupt.
@ k_ra8_int0_bit_dvst
Device-state transition.
@ k_ra8_int0_bit_brdy
Buffer-ready interrupt.
@ k_ra8_int0_bit_ctrt
Control-transfer-stage transition.
@ k_ra8_int0_bit_vbse
VBUS change.
@ k_ra8_int0_bit_nrdy
Buffer-not-ready interrupt.
@ k_ra8_dvsq_powered
Powered (no reset yet).
One pipe's device-visible IN staging buffer (device -> host payload).
bool valid
BVAL pulsed: ready for the host.
One pipe's host-visible OUT staging buffer (host -> device payload).