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:
parent
d100b515d6
commit
259d929c13
6 changed files with 141 additions and 0 deletions
|
@ -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
|
|
@ -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
|
9
kernel/drivers/sunxi_d1_pinctrl/meson.build
Normal file
9
kernel/drivers/sunxi_d1_pinctrl/meson.build
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
kernel_sources += [
|
||||||
|
files(
|
||||||
|
'sunxi_d1_pinctrl.cpp',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
kernel_includes += include_directories(
|
||||||
|
'include'
|
||||||
|
)
|
47
kernel/drivers/sunxi_d1_pinctrl/sunxi_d1_pinctrl.cpp
Normal file
47
kernel/drivers/sunxi_d1_pinctrl/sunxi_d1_pinctrl.cpp
Normal 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
|
|
@ -13,6 +13,7 @@
|
||||||
#include <opensbi/extensions/srst.h>
|
#include <opensbi/extensions/srst.h>
|
||||||
#include <opensbi/extensions/pmu.h>
|
#include <opensbi/extensions/pmu.h>
|
||||||
|
|
||||||
|
#include <sunxi_d1_pinctrl/sunxi_d1_pinctrl.h>
|
||||||
|
|
||||||
void fmt(const char *f, ...) {
|
void fmt(const char *f, ...) {
|
||||||
namespace legacy = drivers::opensbi::legacy;
|
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("uintmax: {} bits\n", sizeof(uintmax_t) * 8);
|
||||||
fmt("HART: {}, DTB: {}\n", hart, dtb);
|
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");
|
fmt("HALT\n");
|
||||||
while(1);
|
while(1);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ kernel_cpp_args = []
|
||||||
kernel_link_args = ['-nostdlib']
|
kernel_link_args = ['-nostdlib']
|
||||||
|
|
||||||
subdir('drivers/opensbi')
|
subdir('drivers/opensbi')
|
||||||
|
subdir('drivers/sunxi_d1_pinctrl')
|
||||||
# subdir('common/dtb')
|
# subdir('common/dtb')
|
||||||
|
|
||||||
includes = [
|
includes = [
|
||||||
|
|
Loading…
Reference in a new issue