/* * 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 #include #include #include 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