Drivers: Added Sunxi pinctrl driver

Works well enough to set bank modes and turn on an LED

Very not complete and needs more testing
This commit is contained in:
Thomas Muller 2022-07-31 23:03:01 -04:00
parent d100b515d6
commit 259d929c13
Signed by: thomas
GPG key ID: AF006EB730564952
6 changed files with 141 additions and 0 deletions

View file

@ -0,0 +1,38 @@
#include <stdint.h>
namespace drivers {
namespace sunxi_d1_pinctrl {
struct [[gnu::aligned(4)]] Port {
uint32_t config[4];
uint32_t data;
uint32_t drive[4];
uint32_t pull[2];
uint32_t _;
};
struct [[gnu::aligned(4)]] PortInt {
uint32_t config[4];
uint32_t control;
uint32_t status;
uint32_t debounce;
uint32_t _;
};
struct [[gnu::aligned(4)]] PIO {
uint32_t mode;
uint32_t control;
uint32_t value;
uint32_t voltage_select;
};
struct [[gnu::aligned(4)]] Registers {
volatile Port ports[7];
volatile uint32_t _[0x34];
volatile PortInt interrupt[7];
volatile uint32_t __[0x10];
volatile PIO pio;
};
} // End namespace sunxi_d1_pinctrl
} // End namespace drivers

View file

@ -0,0 +1,39 @@
#pragma once
#include "registers.h"
#include <stdint.h>
namespace drivers {
namespace sunxi_d1_pinctrl {
enum Bank {
PA,
PB,
PC,
PD,
PE,
PF,
PG,
};
struct SunxiD1Pinctrl {
SunxiD1Pinctrl(void * const addr);
void set_pin_mode(
const Bank bank,
const uint8_t pin,
const uint8_t mode);
void set_pin_state(
const Bank bank,
const uint8_t pin,
const bool state);
bool get_pin_state(
const Bank bank,
const uint8_t pin);
private:
Registers &m_registers;
};
} // End namespace sunxi_d1_pinctrl
} // End namespace drivers

View file

@ -0,0 +1,9 @@
kernel_sources += [
files(
'sunxi_d1_pinctrl.cpp',
),
]
kernel_includes += include_directories(
'include'
)

View file

@ -0,0 +1,47 @@
#include "sunxi_d1_pinctrl/sunxi_d1_pinctrl.h"
namespace drivers {
namespace sunxi_d1_pinctrl {
SunxiD1Pinctrl::SunxiD1Pinctrl(void * const addr) :
m_registers(*reinterpret_cast<Registers *>(addr)) {}
void SunxiD1Pinctrl::set_pin_mode(
const Bank bank,
const uint8_t pin,
const uint8_t mode) {
// Config banks are split up every 8 GPIO pins
// Each bank is 32 bits and configures up to 8 pins
const int config_bank = pin / 8;
// Each config is 4 bits per pin
const int shift_amount = pin % 8 * 4;
const uint32_t mask = 0b1111 << shift_amount;
auto config = m_registers.ports[bank].config[config_bank];
config &= ~mask;
config |= (mode & 0b1111) << shift_amount;
m_registers.ports[bank].config[config_bank] = config;
}
void SunxiD1Pinctrl::set_pin_state(
const Bank bank,
const uint8_t pin,
const bool state) {
const uint32_t mask = 0b1 << pin;
auto data = m_registers.ports[bank].data;
if(state)
data |= mask;
else
data &= ~mask;
m_registers.ports[bank].data = data;
}
bool SunxiD1Pinctrl::get_pin_state(
const Bank bank,
const uint8_t pin) {
return m_registers.ports[bank].data >> pin & 1;
}
} // End namespace sunxi_d1_pinctrl
} // End namespace drivers

View file

@ -13,6 +13,7 @@
#include <opensbi/extensions/srst.h>
#include <opensbi/extensions/pmu.h>
#include <sunxi_d1_pinctrl/sunxi_d1_pinctrl.h>
void fmt(const char *f, ...) {
namespace legacy = drivers::opensbi::legacy;
@ -110,6 +111,12 @@ extern "C" void kmain(unsigned long hart, void *dtb) {
fmt("uintmax: {} bits\n", sizeof(uintmax_t) * 8);
fmt("HART: {}, DTB: {}\n", hart, dtb);
namespace sunxi_d1_pinctrl = drivers::sunxi_d1_pinctrl;
sunxi_d1_pinctrl::SunxiD1Pinctrl pinctrl((void *)0x2000000);
pinctrl.set_pin_mode(sunxi_d1_pinctrl::Bank::PC, 1, 1);
pinctrl.set_pin_state(sunxi_d1_pinctrl::Bank::PC, 1, true);
fmt("HALT\n");
while(1);

View file

@ -13,6 +13,7 @@ kernel_cpp_args = []
kernel_link_args = ['-nostdlib']
subdir('drivers/opensbi')
subdir('drivers/sunxi_d1_pinctrl')
# subdir('common/dtb')
includes = [