mirror of
https://github.com/RGBCube/serenity
synced 2025-06-15 12:52:10 +00:00

As there is no need for a Prekernel on aarch64, the Prekernel code was moved into Kernel itself. The functionality remains the same. SERENITY_KERNEL_AND_INITRD in run.sh specifies a kernel and an inital ramdisk to be used by the emulator. This is needed because aarch64 does not need a Prekernel and the other ones do.
98 lines
3.4 KiB
C++
98 lines
3.4 KiB
C++
/*
|
||
* Copyright (c) 2021, Nico Weber <thakis@chromium.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <Kernel/Arch/aarch64/GPIO.h>
|
||
#include <Kernel/Arch/aarch64/MMIO.h>
|
||
|
||
extern "C" void wait_cycles(int n);
|
||
|
||
namespace Prekernel {
|
||
|
||
// See BCM2835-ARM-Peripherals.pdf section "6 General Purpose I/O" or bcm2711-peripherals.pdf "Chapter 5. General Purpose I/O".
|
||
|
||
// "6.1 Register View" / "5.2 Register View"
|
||
|
||
struct PinData {
|
||
u32 bits[2];
|
||
u32 reserved;
|
||
};
|
||
|
||
struct GPIOControlRegisters {
|
||
u32 function_select[6]; // Every u32 stores a 3-bit function code for 10 pins.
|
||
u32 reserved;
|
||
PinData output_set;
|
||
PinData output_clear;
|
||
PinData level;
|
||
PinData event_detect_status;
|
||
PinData rising_edge_detect_enable;
|
||
PinData falling_edge_detect_enable;
|
||
PinData high_detect_enable;
|
||
PinData low_detect_enable;
|
||
PinData async_rising_edge_detect_enable;
|
||
PinData async_falling_edge_detect_enable;
|
||
u32 pull_up_down_enable;
|
||
PinData pull_up_down_enable_clock;
|
||
u32 test;
|
||
};
|
||
|
||
GPIO::GPIO()
|
||
: m_registers(MMIO::the().peripheral<GPIOControlRegisters>(0x20'0000))
|
||
{
|
||
}
|
||
|
||
GPIO& GPIO::the()
|
||
{
|
||
static GPIO instance;
|
||
return instance;
|
||
}
|
||
|
||
void GPIO::set_pin_function(unsigned pin_number, PinFunction function)
|
||
{
|
||
// pin_number must be <= 53. We can't VERIFY() that since this function runs too early to print assertion failures.
|
||
|
||
unsigned function_select_index = pin_number / 10;
|
||
unsigned function_select_bits_start = (pin_number % 10) * 3;
|
||
|
||
u32 function_bits = m_registers->function_select[function_select_index];
|
||
function_bits = (function_bits & ~(0b111 << function_select_bits_start)) | (static_cast<u32>(function) << function_select_bits_start);
|
||
m_registers->function_select[function_select_index] = function_bits;
|
||
}
|
||
|
||
void GPIO::internal_enable_pins(u32 enable[2], PullUpDownState state)
|
||
{
|
||
// Section "GPIO Pull-up/down Clock Registers (GPPUDCLKn)":
|
||
// The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on
|
||
// the respective GPIO pins. These registers must be used in conjunction with the GPPUD
|
||
// register to effect GPIO Pull-up/down changes. The following sequence of events is
|
||
// required:
|
||
// 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither
|
||
// to remove the current Pull-up/down)
|
||
m_registers->pull_up_down_enable = static_cast<u32>(state);
|
||
|
||
// 2. Wait 150 cycles – this provides the required set-up time for the control signal
|
||
wait_cycles(150);
|
||
|
||
// 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to
|
||
// modify – NOTE only the pads which receive a clock will be modified, all others will
|
||
// retain their previous state.
|
||
m_registers->pull_up_down_enable_clock.bits[0] = enable[0];
|
||
m_registers->pull_up_down_enable_clock.bits[1] = enable[1];
|
||
|
||
// 4. Wait 150 cycles – this provides the required hold time for the control signal
|
||
wait_cycles(150);
|
||
|
||
// 5. Write to GPPUD to remove the control signal
|
||
m_registers->pull_up_down_enable = 0;
|
||
|
||
// 6. Write to GPPUDCLK0/1 to remove the clock
|
||
m_registers->pull_up_down_enable_clock.bits[0] = 0;
|
||
m_registers->pull_up_down_enable_clock.bits[1] = 0;
|
||
|
||
// bcm2711-peripherals.pdf documents GPIO_PUP_PDN_CNTRL_REG[4] registers that store 2 bits state per register, similar to function_select.
|
||
// I don't know if the RPi3 has that already, so this uses the old BCM2835 approach for now.
|
||
}
|
||
|
||
}
|