1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <plat/gpio.h>
18 #include <plat/usart.h>
19 #include <plat/pwr.h>
20 #include <usart.h>
21 #include <gpio.h>
22
23 struct StmUsart {
24 volatile uint16_t SR;
25 uint8_t unused0[2];
26 volatile uint16_t DR;
27 uint8_t unused1[2];
28 volatile uint16_t BRR;
29 uint8_t unused2[2];
30 volatile uint16_t CR1;
31 uint8_t unused3[2];
32 volatile uint16_t CR2;
33 uint8_t unused4[2];
34 volatile uint16_t CR3;
35 uint8_t unused5[2];
36 volatile uint16_t GTPR;
37 uint8_t unused6[2];
38 };
39
40 static const uint32_t mUsartPorts[] = {
41 USART1_BASE,
42 USART2_BASE,
43 USART3_BASE,
44 UART4_BASE,
45 UART5_BASE,
46 USART6_BASE,
47 };
48
49 static const uint32_t mUsartPeriphs[] = {
50 PERIPH_APB2_USART1,
51 PERIPH_APB1_USART2,
52 PERIPH_APB1_USART3,
53 PERIPH_APB1_UART4,
54 PERIPH_APB1_UART5,
55 PERIPH_APB2_USART6,
56 };
57
58 static uint8_t mUsartBusses[] = {
59 PERIPH_BUS_APB2,
60 PERIPH_BUS_APB1,
61 PERIPH_BUS_APB1,
62 PERIPH_BUS_APB1,
63 PERIPH_BUS_APB1,
64 PERIPH_BUS_APB2,
65 };
66
67 static bool mUsartHasFlowControl[] = {
68 true,
69 true,
70 true,
71 false,
72 false,
73 true,
74 };
75
76 static enum StmGpioAltFunc mUsartAlt[] = {
77 GPIO_AF_USART1,
78 GPIO_AF_USART2,
79 GPIO_AF00,
80 GPIO_AF00,
81 GPIO_AF00,
82 GPIO_AF_USART6,
83 };
84
usartOpen(struct usart * __restrict usart,UsartPort port,uint32_t txGpioNum,uint32_t rxGpioNum,uint32_t baud,UsartDataBitsCfg data_bits,UsatStopBitsCfg stop_bits,UsartParityCfg parity,UsartFlowControlCfg flow_control)85 void usartOpen(struct usart* __restrict usart, UsartPort port,
86 uint32_t txGpioNum, uint32_t rxGpioNum,
87 uint32_t baud, UsartDataBitsCfg data_bits,
88 UsatStopBitsCfg stop_bits, UsartParityCfg parity,
89 UsartFlowControlCfg flow_control)
90 {
91 static const uint16_t stopBitsVals[] = {0x1000, 0x0000, 0x3000, 0x2000}; // indexed by UsatStopBitsCfg
92 static const uint16_t wordLengthVals[] = {0x0000, 0x1000}; // indexed by UsartDataBitsCfg
93 static const uint16_t parityVals[] = {0x0000, 0x0400, 0x0600}; // indexed by UsartParityCfg
94 static const uint16_t flowCtrlVals[] = {0x0000, 0x0100, 0x0200, 0x0300}; // indexed by UsartFlowControlCfg
95 struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit = --port];
96 uint32_t baseClk, div, intPart, fraPart;
97
98 /* configure tx/rx gpios */
99
100 usart->rx = gpioRequest(rxGpioNum); /* rx */
101 gpioConfigAlt(usart->rx, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_OUT_PUSH_PULL, mUsartAlt[port]);
102 usart->tx = gpioRequest(txGpioNum); /* tx */
103 gpioConfigAlt(usart->tx, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_OUT_PUSH_PULL, mUsartAlt[port]);
104
105 /* enable clock */
106 pwrUnitClock(mUsartBusses[port], mUsartPeriphs[port], true);
107
108 /* sanity checks */
109 if (!mUsartHasFlowControl[port])
110 flow_control = USART_FLOW_CONTROL_NONE;
111
112 /* basic config as required + oversample by 8, tx+rx on */
113 block->CR2 = (block->CR2 &~ 0x3000) | stopBitsVals[stop_bits];
114 block->CR1 = (block->CR1 &~ 0x1600) | wordLengthVals[data_bits] | parityVals[parity] | 0x800C;
115 block->CR3 = (block->CR3 &~ 0x0300) | flowCtrlVals[flow_control];
116
117 /* clocking calc */
118 baseClk = pwrGetBusSpeed(mUsartBusses[port]);
119 div = (baseClk * 25) / (baud * 2);
120 intPart = div / 100;
121 fraPart = div % 100;
122
123 /* clocking munging */
124 intPart = intPart << 4;
125 fraPart = ((fraPart * 8 + 50) / 100) & 7;
126 block->BRR = intPart | fraPart;
127
128 /* enable */
129 block->CR1 |= 0x2000;
130 }
131
usartClose(const struct usart * __restrict usart)132 void usartClose(const struct usart* __restrict usart)
133 {
134 struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
135
136 /* Disable USART */
137 block->CR1 &=~ 0x2000;
138
139 /* Disable USART clock */
140 pwrUnitClock(mUsartBusses[usart->unit], mUsartPeriphs[usart->unit], false);
141
142 /* Release gpios */
143 gpioRelease(usart->rx);
144 gpioRelease(usart->tx);
145 }
146
147 /*
148 * don't use this immediately after usart initialization
149 * the test is valid only after the first char has been sent out
150 */
usartFlush(const struct usart * __restrict usart)151 void usartFlush(const struct usart* __restrict usart)
152 {
153 struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
154
155 while ((block->SR & 0x00c0) != 0x00c0);
156 }
157
usartPutchar(const struct usart * __restrict usart,char c)158 void usartPutchar(const struct usart* __restrict usart, char c)
159 {
160 struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
161
162 /* wait for ready */
163 while (!(block->SR & 0x0080));
164
165 /* send */
166 block->DR = (uint8_t)c;
167 }
168