summaryrefslogtreecommitdiff
path: root/src/portable/renesas/rusb2/rusb2_ra.h
blob: 0954d0d25af55697b300012073c383aa9bf3beb0 (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
/*
 * SPDX-FileCopyrightText: Copyright (c) 2022 Rafael Silva (@perigoso)
 * SPDX-FileCopyrightText: Copyright (c) 2022 Ha Thach (tinyusb.org)
 * SPDX-License-Identifier: MIT
 *
 * This file is part of the TinyUSB stack.
 */

#ifndef _RUSB2_RA_H_
#define _RUSB2_RA_H_

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#pragma GCC diagnostic ignored "-Wundef"

// extra push due to https://github.com/renesas/fsp/pull/278
#pragma GCC diagnostic push
#endif

/* renesas fsp api */
#include "bsp_api.h"

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

// IAR does not have __builtin_ctz
#if defined(__ICCARM__)
  #define __builtin_ctz(x)   __iar_builtin_CLZ(__iar_builtin_RBIT(x))
#endif

//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+

typedef struct {
  uint32_t reg_base;
  int32_t irqnum;
}rusb2_controller_t;

#if defined(BSP_MCU_GROUP_RA6M5) || defined(BSP_MCU_GROUP_RA6M3) || (BSP_CFG_MCU_PART_SERIES == 8)
  #define RUSB2_SUPPORT_HIGHSPEED
  #define RUSB2_CONTROLLER_COUNT 2

  #define rusb2_is_highspeed_rhport(_p)  (_p == 1)
  #define rusb2_is_highspeed_reg(_reg)   (_reg == RUSB2_REG(1))

  // UTMI PHY reference clock is the main oscillator: PHYSET.CLKSEL must match the board XTAL
  // before the PHY PLL is released (RA6M5 UM R01UH0891 29.2.17: 00=12 MHz, 10=20 MHz,
  // 11=24 MHz reset default). EK-RA6M5 runs 24 MHz (default works); EK-RA8M1 runs 20 MHz and
  // never locks/chirps on the default. A board with a non-standard USB clocking scheme can
  // pre-define RUSB2_PHYSET_CLKSEL_VALUE to override this selection.
  #ifndef RUSB2_PHYSET_CLKSEL_VALUE
    #if   BSP_CFG_XTAL_HZ == 12000000
      #define RUSB2_PHYSET_CLKSEL_VALUE 0u
    #elif BSP_CFG_XTAL_HZ == 20000000
      #define RUSB2_PHYSET_CLKSEL_VALUE 2u
    #elif BSP_CFG_XTAL_HZ == 24000000
      #define RUSB2_PHYSET_CLKSEL_VALUE 3u
    #else
      #error "USBHS UTMI PHY: no PHYSET.CLKSEL encoding for this BSP_CFG_XTAL_HZ; define RUSB2_PHYSET_CLKSEL_VALUE"
    #endif
  #endif
#else
  #define RUSB2_CONTROLLER_COUNT 1

  #define rusb2_is_highspeed_rhport(_p)  (false)
  #define rusb2_is_highspeed_reg(_reg)   (false)
#endif

extern rusb2_controller_t rusb2_controller[];
#define RUSB2_REG(_p)      ((rusb2_reg_t*) rusb2_controller[_p].reg_base)

//--------------------------------------------------------------------+
// RUSB2 API
//--------------------------------------------------------------------+

TU_ATTR_ALWAYS_INLINE static inline void rusb2_module_start(uint8_t rhport, bool start) {
  uint32_t const mask = 1U << (11+rhport);
  if (start) {
    R_MSTP->MSTPCRB &= ~mask;
  }else {
    R_MSTP->MSTPCRB |= mask;
  }
}

TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport) {
  NVIC_EnableIRQ(rusb2_controller[rhport].irqnum);
}

TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport) {
  NVIC_DisableIRQ(rusb2_controller[rhport].irqnum);
}

// MCU specific PHY init
TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void) {
}

#ifdef RUSB2_SUPPORT_HIGHSPEED
// UTMI PHY power-up per the FSP reference sequence (r_usb_preg_access.c), shared by dcd_init and
// hcd_init: program CLKSEL to the board XTAL while the PHY is powered down (DIRPD=1), 1 us,
// release DIRPD, 1 ms, release PLLRESET, then wait for PLL lock. Changing CLKSEL as the PHY
// powers up gets mis-sampled (EK-RA8M1, 20 MHz).
static inline void rusb2_utmi_phy_powerup(rusb2_reg_t* rusb) {
  uint16_t physet = rusb->PHYSET | RUSB2_PHYSET_DIRPD_Msk;
  rusb->PHYSET = physet;
  #ifdef RUSB2_PHYSET_CLKSEL_VALUE
  physet = (uint16_t) ((physet & ~RUSB2_PHYSET_CLKSEL_Msk) |
                       (RUSB2_PHYSET_CLKSEL_VALUE << RUSB2_PHYSET_CLKSEL_Pos));
  rusb->PHYSET = physet;
  #endif
  R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MICROSECONDS);
  physet &= (uint16_t) ~RUSB2_PHYSET_DIRPD_Msk;
  rusb->PHYSET = physet;
  R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS);
  rusb->PHYSET_b.PLLRESET = 0;

  // set UTMI to operating mode and wait for PLL lock confirmation
  rusb->LPSTS_b.SUSPENDM = 1;
  while (!rusb->PLLSTA_b.PLLLOCK) {}
}
#endif

#ifdef __cplusplus
}
#endif

#endif /* _RUSB2_RA_H_ */