diff --git a/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/registers.h b/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/registers.h new file mode 100644 index 0000000..8c4c14c --- /dev/null +++ b/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/registers.h @@ -0,0 +1,38 @@ +#include + +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 diff --git a/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/sunxi_d1_pinctrl.h b/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/sunxi_d1_pinctrl.h new file mode 100644 index 0000000..4d5adaa --- /dev/null +++ b/kernel/drivers/sunxi_d1_pinctrl/include/sunxi_d1_pinctrl/sunxi_d1_pinctrl.h @@ -0,0 +1,39 @@ +#pragma once + +#include "registers.h" +#include + +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 diff --git a/kernel/drivers/sunxi_d1_pinctrl/meson.build b/kernel/drivers/sunxi_d1_pinctrl/meson.build new file mode 100644 index 0000000..f157d0a --- /dev/null +++ b/kernel/drivers/sunxi_d1_pinctrl/meson.build @@ -0,0 +1,9 @@ +kernel_sources += [ + files( + 'sunxi_d1_pinctrl.cpp', + ), +] + +kernel_includes += include_directories( + 'include' +) diff --git a/kernel/drivers/sunxi_d1_pinctrl/sunxi_d1_pinctrl.cpp b/kernel/drivers/sunxi_d1_pinctrl/sunxi_d1_pinctrl.cpp new file mode 100644 index 0000000..07dd5d6 --- /dev/null +++ b/kernel/drivers/sunxi_d1_pinctrl/sunxi_d1_pinctrl.cpp @@ -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(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 diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 2e2209b..856f366 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include #include +#include 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); diff --git a/kernel/meson.build b/kernel/meson.build index c662b20..667e199 100644 --- a/kernel/meson.build +++ b/kernel/meson.build @@ -13,6 +13,7 @@ kernel_cpp_args = [] kernel_link_args = ['-nostdlib'] subdir('drivers/opensbi') +subdir('drivers/sunxi_d1_pinctrl') # subdir('common/dtb') includes = [