484a79fcc0
Add INIT_ATTR to some low-hanging fruit in the X1000 code: GPIO init, GPIO initial state tables, clock init, and DMA init. Change-Id: Ia02b20945da1bbed103e2e01eaf60553eb5f72d4
171 lines
5 KiB
C
171 lines
5 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2021 Aidan MacDonald
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef __GPIO_X1000_H__
|
|
#define __GPIO_X1000_H__
|
|
|
|
#include "x1000/gpio.h"
|
|
#include "config.h"
|
|
|
|
/* GPIO port numbers */
|
|
#define GPIO_A 0
|
|
#define GPIO_B 1
|
|
#define GPIO_C 2
|
|
#define GPIO_D 3
|
|
#define GPIO_Z 7
|
|
|
|
/* GPIO function bits */
|
|
#define GPIO_F_PULL 16
|
|
#define GPIO_F_INT 8
|
|
#define GPIO_F_MASK 4
|
|
#define GPIO_F_PAT1 2
|
|
#define GPIO_F_PAT0 1
|
|
|
|
/* GPIO function numbers */
|
|
#define GPIOF_DEVICE(i) ((i)&3)
|
|
#define GPIOF_OUTPUT(i) (0x4|((i)&1))
|
|
#define GPIOF_INPUT 0x16
|
|
#define GPIOF_IRQ_LEVEL(i) (0x1c|((i)&1))
|
|
#define GPIOF_IRQ_EDGE(i) (0x1e|((i)&1))
|
|
|
|
/* GPIO pin numbers */
|
|
#define GPION_CREATE(port, pin) ((((port) & 3) << 5) | ((pin) & 0x1f))
|
|
#define GPION_PORT(gpio) (((gpio) >> 5) & 3)
|
|
#define GPION_PIN(gpio) ((gpio) & 0x1f)
|
|
#define GPION_MASK(gpio) (1u << GPION_PIN(gpio))
|
|
|
|
/* Easy pin number macros */
|
|
#define GPIO_PA(x) GPION_CREATE(GPIO_A, x)
|
|
#define GPIO_PB(x) GPION_CREATE(GPIO_B, x)
|
|
#define GPIO_PC(x) GPION_CREATE(GPIO_C, x)
|
|
#define GPIO_PD(x) GPION_CREATE(GPIO_D, x)
|
|
|
|
/* GPIO number to IRQ number (need to include "irq-x1000.h") */
|
|
#define GPIO_TO_IRQ(gpio) IRQ_GPIO(GPION_PORT(gpio), GPION_PIN(gpio))
|
|
|
|
/* Pingroup settings are used for system devices */
|
|
struct pingroup_setting {
|
|
int port;
|
|
uint32_t pins;
|
|
int func;
|
|
};
|
|
|
|
/* GPIO settings are used for single pins under software control */
|
|
struct gpio_setting {
|
|
int gpio;
|
|
int func;
|
|
};
|
|
|
|
/* Target pins are defined as GPIO_XXX constants usable with the GPIO API */
|
|
enum {
|
|
#define DEFINE_GPIO(_name, _gpio, _func) GPIO_##_name = _gpio,
|
|
#define DEFINE_PINGROUP(...)
|
|
#include "gpio-target.h"
|
|
#undef DEFINE_GPIO
|
|
#undef DEFINE_PINGROUP
|
|
GPIO_NONE = -1,
|
|
};
|
|
|
|
/* These are pin IDs which index gpio_settings */
|
|
enum {
|
|
#define DEFINE_GPIO(_name, ...) PIN_##_name,
|
|
#define DEFINE_PINGROUP(...)
|
|
#include "gpio-target.h"
|
|
#undef DEFINE_GPIO
|
|
#undef DEFINE_PINGROUP
|
|
PIN_COUNT,
|
|
};
|
|
|
|
/* Pingroup IDs which index pingroup_settings */
|
|
enum {
|
|
#define DEFINE_GPIO(...)
|
|
#define DEFINE_PINGROUP(_name, ...) PINGROUP_##_name,
|
|
#include "gpio-target.h"
|
|
#undef DEFINE_GPIO
|
|
#undef DEFINE_PINGROUP
|
|
PINGROUP_COUNT,
|
|
};
|
|
|
|
/* called at early init to set up GPIOs */
|
|
extern void gpio_init(void) INIT_ATTR;
|
|
|
|
/* Use GPIO Z to reconfigure several pins atomically */
|
|
extern void gpioz_configure(int port, uint32_t pins, int func);
|
|
|
|
static inline void gpio_set_function(int gpio, int func)
|
|
{
|
|
gpioz_configure(GPION_PORT(gpio), GPION_MASK(gpio), func);
|
|
}
|
|
|
|
static inline int gpio_get_level(int gpio)
|
|
{
|
|
return REG_GPIO_PIN(GPION_PORT(gpio)) & GPION_MASK(gpio) ? 1 : 0;
|
|
}
|
|
|
|
static inline void gpio_set_level(int gpio, int value)
|
|
{
|
|
if(value)
|
|
jz_set(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
else
|
|
jz_clr(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
}
|
|
|
|
static inline void gpio_set_pull(int gpio, int state)
|
|
{
|
|
if(state)
|
|
jz_set(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
else
|
|
jz_clr(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
}
|
|
|
|
static inline void gpio_mask_irq(int gpio, int mask)
|
|
{
|
|
if(mask)
|
|
jz_set(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
else
|
|
jz_clr(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
|
|
}
|
|
|
|
#define gpio_set_irq_level gpio_set_level
|
|
#define gpio_enable_irq(gpio) gpio_mask_irq((gpio), 0)
|
|
#define gpio_disable_irq(gpio) gpio_mask_irq((gpio), 1)
|
|
|
|
/* Helper function for edge-triggered IRQs when you want to get an
|
|
* interrupt on both the rising and falling edges. The hardware can
|
|
* only be set up to interrupt on one edge, so interrupt handlers
|
|
* can call this function to flip the trigger to the other edge.
|
|
*
|
|
* Despite the name, this doesn't depend on the currently set edge,
|
|
* it just reads the GPIO state and sets up an edge trigger to detect
|
|
* a change to the other state -- if some transitions were missed the
|
|
* IRQ trigger may remain unchanged.
|
|
*
|
|
* It can be safely used to initialize the IRQ level.
|
|
*/
|
|
static inline void gpio_flip_edge_irq(int gpio)
|
|
{
|
|
if(gpio_get_level(gpio))
|
|
gpio_set_irq_level(gpio, 0);
|
|
else
|
|
gpio_set_irq_level(gpio, 1);
|
|
}
|
|
|
|
#endif /* __GPIO_X1000_H__ */
|