| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <plat/gpio.h> |
| #include <plat/pwr.h> |
| #include <gpio.h> |
| #include <cpu.h> |
| |
| struct StmGpio { |
| volatile uint32_t MODER; |
| volatile uint32_t OTYPER; |
| volatile uint32_t OSPEEDR; |
| volatile uint32_t PUPDR; |
| volatile uint32_t IDR; |
| volatile uint32_t ODR; |
| volatile uint32_t BSRR; |
| volatile uint32_t LCKR; |
| volatile uint32_t AFR[2]; |
| }; |
| |
| static const uint32_t mGpioPeriphs[] = { |
| PERIPH_AHB1_GPIOA, |
| PERIPH_AHB1_GPIOB, |
| PERIPH_AHB1_GPIOC, |
| PERIPH_AHB1_GPIOD, |
| PERIPH_AHB1_GPIOE, |
| PERIPH_AHB1_GPIOF, |
| PERIPH_AHB1_GPIOG, |
| PERIPH_AHB1_GPIOH, |
| PERIPH_AHB1_GPIOI, |
| }; |
| |
| static const uint32_t mGpioBases[] = { |
| GPIOA_BASE, |
| GPIOB_BASE, |
| GPIOC_BASE, |
| GPIOD_BASE, |
| GPIOE_BASE, |
| GPIOF_BASE, |
| GPIOG_BASE, |
| GPIOH_BASE, |
| GPIOI_BASE, |
| }; |
| |
| static void gpioSetWithNum(uint32_t gpioNum, bool value); |
| |
| |
| struct Gpio* gpioRequest(uint32_t number) |
| { |
| return (struct Gpio*)(((uintptr_t)number) + GPIO_HANDLE_OFFSET); |
| } |
| |
| void gpioRelease(struct Gpio* __restrict gpio) |
| { |
| (void)gpio; |
| } |
| |
| static enum StmGpioSpeed gpioSpeedFromRequestedSpeed(int32_t requestedSpeed) |
| { |
| static const enum StmGpioSpeed mStandardSpeeds[] = { |
| [-1 - GPIO_SPEED_BEST_POWER ] = GPIO_SPEED_LOW, |
| [-1 - GPIO_SPEED_BEST_SPEED ] = GPIO_SPEED_HIGH, |
| [-1 - GPIO_SPEED_DEFAULT ] = GPIO_SPEED_MEDIUM, |
| [-1 - GPIO_SPEED_1MHZ_PLUS ] = GPIO_SPEED_LOW, |
| [-1 - GPIO_SPEED_3MHZ_PLUS ] = GPIO_SPEED_LOW, |
| [-1 - GPIO_SPEED_5MHZ_PLUS ] = GPIO_SPEED_MEDIUM, |
| [-1 - GPIO_SPEED_10MHZ_PLUS ] = GPIO_SPEED_MEDIUM, |
| [-1 - GPIO_SPEED_15MHZ_PLUS ] = GPIO_SPEED_MEDIUM, |
| [-1 - GPIO_SPEED_20MHZ_PLUS ] = GPIO_SPEED_MEDIUM, |
| [-1 - GPIO_SPEED_30MHZ_PLUS ] = GPIO_SPEED_FAST, |
| [-1 - GPIO_SPEED_50MHZ_PLUS ] = GPIO_SPEED_FAST, |
| [-1 - GPIO_SPEED_100MHZ_PLUS ] = GPIO_SPEED_FAST, |
| [-1 - GPIO_SPEED_150MHZ_PLUS ] = GPIO_SPEED_FAST, //this is not fast enough, but it is all we can do |
| [-1 - GPIO_SPEED_150MHZ_PLUS ] = GPIO_SPEED_FAST, //this is not fast enough, but it is all we can do |
| }; |
| |
| if (requestedSpeed >= 0) |
| return requestedSpeed; |
| else |
| return mStandardSpeeds[-requestedSpeed - 1]; |
| } |
| |
| static void gpioConfigWithNum(uint32_t gpioNum, int32_t gpioSpeed, enum GpioPullMode pull, enum GpioOpenDrainMode output) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t shift_1b = gpioNum & GPIO_PIN_MASK; |
| const uint32_t shift_2b = (gpioNum & GPIO_PIN_MASK) * 2; |
| const uint32_t mask_1b = (1UL << shift_1b); |
| const uint32_t mask_2b = (3UL << shift_2b); |
| |
| /* unit clock */ |
| pwrUnitClock(PERIPH_BUS_AHB1, mGpioPeriphs[gpioNum >> GPIO_PORT_SHIFT], true); |
| |
| /* speed */ |
| block->OSPEEDR = (block->OSPEEDR & ~mask_2b) | (((uint32_t)gpioSpeedFromRequestedSpeed(gpioSpeed)) << shift_2b); |
| |
| /* pull ups/downs */ |
| block->PUPDR = (block->PUPDR & ~mask_2b) | (((uint32_t)pull) << shift_2b); |
| /* push/pull or open drain */ |
| if (output == GPIO_OUT_PUSH_PULL) |
| block->OTYPER &= ~mask_1b; |
| else |
| block->OTYPER |= mask_1b; |
| } |
| |
| static void gpioConfigInputWithNum(uint32_t gpioNum, int32_t gpioSpeed, enum GpioPullMode pull) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t shift_2b = (gpioNum & GPIO_PIN_MASK) * 2; |
| const uint32_t mask_2b = (3UL << shift_2b); |
| |
| gpioConfigWithNum(gpioNum, gpioSpeed, pull, GPIO_OUT_PUSH_PULL); |
| |
| /* direction */ |
| block->MODER = (block->MODER & ~mask_2b) | (((uint32_t)GPIO_MODE_IN) << shift_2b); |
| } |
| |
| void gpioConfigInput(const struct Gpio* __restrict gpioHandle, int32_t gpioSpeed, enum GpioPullMode pull) |
| { |
| if (gpioHandle) |
| gpioConfigInputWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET, gpioSpeed, pull); |
| } |
| |
| static void gpioConfigOutputWithNum(uint32_t gpioNum, int32_t gpioSpeed, enum GpioPullMode pull, enum GpioOpenDrainMode output, bool value) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t shift_2b = (gpioNum & GPIO_PIN_MASK) * 2; |
| const uint32_t mask_2b = (3UL << shift_2b); |
| |
| gpioConfigWithNum(gpioNum, gpioSpeed, pull, output); |
| |
| /* set the initial output value */ |
| gpioSetWithNum(gpioNum, value); |
| |
| /* direction */ |
| block->MODER = (block->MODER & ~mask_2b) | (((uint32_t)GPIO_MODE_OUT) << shift_2b); |
| } |
| |
| void gpioConfigOutput(const struct Gpio* __restrict gpioHandle, int32_t gpioSpeed, enum GpioPullMode pull, enum GpioOpenDrainMode output, bool value) |
| { |
| if (gpioHandle) |
| gpioConfigOutputWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET, gpioSpeed, pull, output, value); |
| } |
| |
| static void gpioConfigAltWithNum(uint32_t gpioNum, int32_t gpioSpeed, enum GpioPullMode pull, enum GpioOpenDrainMode output, uint32_t altFunc) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t pinNo = gpioNum & GPIO_PIN_MASK; |
| const uint32_t regNo = pinNo >> (GPIO_PORT_SHIFT - 1); |
| const uint32_t nibbleNo = pinNo & (GPIO_PIN_MASK >> 1); |
| const uint32_t shift_2b = pinNo * 2; |
| const uint32_t shift_4b = nibbleNo * 4; |
| const uint32_t mask_2b = (3UL << shift_2b); |
| const uint32_t mask_4b = (15UL << shift_4b); |
| |
| gpioConfigWithNum(gpioNum, gpioSpeed, pull, output); |
| |
| /* assign function */ |
| block->AFR[regNo] = (block->AFR[regNo] & ~mask_4b) | (((uint32_t)altFunc) << shift_4b); |
| |
| /* direction */ |
| block->MODER = (block->MODER & ~mask_2b) | (((uint32_t)GPIO_MODE_ALTERNATE) << shift_2b); |
| } |
| |
| void gpioConfigAlt(const struct Gpio* __restrict gpioHandle, int32_t gpioSpeed, enum GpioPullMode pull, enum GpioOpenDrainMode output, uint32_t altFunc) |
| { |
| if (gpioHandle) |
| gpioConfigAltWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET, gpioSpeed, pull, output, altFunc); |
| } |
| |
| static void gpioConfigAnalogWithNum(uint32_t gpioNum) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t pinNo = gpioNum & GPIO_PIN_MASK; |
| const uint32_t shift_2b = pinNo * 2; |
| const uint32_t mask_2b = (3UL << shift_2b); |
| |
| gpioConfigWithNum(gpioNum, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_OUT_OPEN_DRAIN); |
| |
| /* I/O configuration */ |
| block->MODER = (block->MODER & ~mask_2b) | (((uint32_t)GPIO_MODE_ANALOG) << shift_2b); |
| } |
| |
| void gpioConfigAnalog(const struct Gpio* __restrict gpioHandle) |
| { |
| if (gpioHandle) |
| gpioConfigAnalogWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET); |
| } |
| |
| static void gpioSetWithNum(uint32_t gpioNum, bool value) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t shift_1b = gpioNum & GPIO_PIN_MASK; |
| const uint32_t mask_set_1b = (1UL << (0 + shift_1b)); |
| const uint32_t mask_clr_1b = (1UL << (16 + shift_1b)); |
| |
| block->BSRR = value ? mask_set_1b : mask_clr_1b; |
| } |
| |
| void gpioSet(const struct Gpio* __restrict gpioHandle, bool value) |
| { |
| if (gpioHandle) |
| gpioSetWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET, value); |
| } |
| |
| static bool gpioGetWithNum(uint32_t gpioNum) |
| { |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[gpioNum >> GPIO_PORT_SHIFT]; |
| const uint32_t shift_1b = gpioNum & GPIO_PIN_MASK; |
| const uint32_t mask_1b = (1UL << shift_1b); |
| |
| return !!(block->IDR & mask_1b); |
| } |
| |
| bool gpioGet(const struct Gpio* __restrict gpioHandle) |
| { |
| return gpioHandle ? gpioGetWithNum((uint32_t)gpioHandle - GPIO_HANDLE_OFFSET) : 0; |
| } |
| |
| |
| #ifdef DEBUG_UART_PIN |
| |
| //this function makes more assumptions than i'd care to list, sorry... |
| void gpioBitbangedUartOut(uint32_t chr) |
| { |
| static const uint32_t bsrrVals[] = {(1 << (DEBUG_UART_PIN & GPIO_PIN_MASK)) << 16, (1 << (DEBUG_UART_PIN & GPIO_PIN_MASK))}; |
| struct StmGpio *block = (struct StmGpio*)mGpioBases[DEBUG_UART_PIN >> GPIO_PORT_SHIFT]; |
| uint32_t bits[10], *bitsP = bits, base = (uint32_t)&block->BSRR; |
| static bool setup = 0; |
| uint64_t state; |
| uint32_t i; |
| |
| if (!setup) { |
| struct Gpio *gpio = gpioRequest(DEBUG_UART_PIN); |
| |
| if (!gpio) |
| return; |
| |
| setup = true; |
| gpioConfigOutput(gpio, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_OUT_PUSH_PULL, true); |
| } |
| |
| bits[0] = bsrrVals[0]; |
| for (i = 0; i < 8; i++, chr >>= 1) |
| bits[i + 1] = bsrrVals[chr & 1]; |
| bits[9] = bsrrVals[1]; |
| |
| #define SENDBIT "ldr %0, [%1], #4 \n\t" \ |
| "str %0, [%2] \n\t" \ |
| "nop \n\t" \ |
| "nop \n\t" \ |
| "nop \n\t" \ |
| "nop \n\t" \ |
| "nop \n\t" \ |
| "nop \n\t" |
| |
| state = cpuIntsOff(); |
| asm volatile( |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| SENDBIT |
| :"=r"(i), "=r"(bitsP), "=r"(base) |
| :"0"(i), "1"(bitsP), "2"(base) |
| :"memory","cc" |
| ); |
| cpuIntsRestore(state); |
| } |
| |
| |
| #endif |
| |
| |
| |
| |