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 
usartPutchar(const struct usart * __restrict usart,char c)147 void usartPutchar(const struct usart* __restrict usart, char c)
148 {
149     struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
150 
151     /* wait for ready */
152     while (!(block->SR & 0x0080));
153 
154     /* send */
155     block->DR = (uint8_t)c;
156 }
157