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/inc/gpio.h> 18 #include <plat/inc/usart.h> 19 #include <plat/inc/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 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 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 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