SoC and Drivers
SoC: System-on-Chip
On a silicon die, traditionally, this was just a processor, but now it can include a lot more. The following two graphics show what is can be inside a SoC
Some SoC's you might be familiar with:
- TI MSP432: More like a microcontroller (more like the righ-hand SoC)
- Processor Core
- A couple serial controllers
- A couple of ADCs
- A DAC
- Power control module
- Built in clock select
- Timers
- Raspberry Pi (more like the left-hand SoC)
Remember back to CPE 329, to control peripheral, you would include a header file, and that header file would have structs and variables:
Under the hood, the way most systems work (including ARM systems), all I/O
commands to peripheral are done using memory mapped IO (MMIO).
In the SoC diagram, to send data from the processor to the graphics engine,
loads and stores are done to send data between the two.
The code snippet below shows writing a 1 to address 0x20000000
To know what this actually does, you would need two things:
- TI would need to give you the address range of all memory peripheral
- TI would need to provide the documentation for the accelerators themselves so you would know what bit in the address space corresponds to what.
However, if things were left at this level, programmers would need to remember,
or look up all of this every time they want to use a peripheral. This is
abstracted with things like the msp432.h header file.
There are a couple of issues with leaving things at such a low level. Programmers don't want to have to remember things at such a low level, and the code is no longer portable.
Generally, to separate low level block commands from app code, we build drivers.
Driver Definition
Code that takes a high-level function, and translates it into peripheral control signals. These may be customized per OS.
For example, for the UART module, you may have a set_baud() function. In Linux,
for instance, you would need to register the driver with the kernel (key part of
OS) and/or since Linux is a monolithic kernel, you may have to compile the kernel
with the driver. Linux mandates some driver kernel interactions and for common
device types, Linux will mandate certain generic high-level function calls that
the driver must support.
For URAT, the following may be an example:
Using these standard signatures allow programs to work agnostic of the underlying
driver. If you have a device that Linux is aware of, and there is a driver for
that device, Linux will put a pointer to that driver in the /dev/ directory.
For instance, if you connect a USB serial device, it will show up as
/dev/usbtty0. Memory will show up as /dev/mem. So, for DMA, you just need
to point it to /dev/mem.
ARM: devicetree.dtb contains a listing of peripherals and address ranges. For
instance, it may look something like:
x86: BIOS/UEFI