- Device tree configuration file has information about a peripherals's HW irq number
- IRQ chip driver do below:
- maps HW irq number to software irq number
- find out which HW irq is raised
- Peripheral driver find out which software irq this device is associated with, and a interrupt handler is registered.
=================================================== DRAM offset/size configuration and image relocation Start up code of the zImage. setup page table get size of decompressed kernel size at the end of the compressed data relocate the zImage code setup BSS setup stack (due to DRAM bug, stack is put on SPM) jump to decompress_kernel (in Misc.c) setup MMU mapping, hard coded mapping for DRAM area turn on cachable and bufferable for DRAM =================================================== /arch/arm/boot/compressed/head.S #define HELIOSX_DRAM_REGION_BASE (CONFIG_HELIOSX_DRAM_REGION_BASE) #define HELIOSX_DRAM_SIZE (0x08000000) // 128M #define HELIOSX_DRAM_START (HELIOSX_DRAM_REGION_BASE + 0x08000000) #define HELIOSX_DRAM_END (HELIOSX_DRAM_START + HELIOSX_DRAM_SIZE) #define HELIOSX_ZRELADDR (HELIOSX_DRAM_START + TEXT_OFFSET) ... /* xgu hack, just set MMU to map all the RAM between 0x08000000 - 0x10000000 * everything is hardcoded * r4 = 0x0a000000 * r3 = 0x09f00000 */ __setup_mmu_heliosx: @sub r3, r4, #0x00100000 @ 1M for Page directory, to place 170000, not ok @mov r3, #0x1b000000 @ hard code to a place add r3, r4, #0x00800000 @ Add 8M offset to 0x08000000 mov r0, r3 @ table of index mov r9, #HELIOSX_DRAM_START @ start of RAM mov r10, #HELIOSX_DRAM_END @ end of RAM mov r1, #0x12 @ section mapping orr r1, r1, #3 << 10 @ AP=11 ... =================================================== Utility to output number MMU setting, remapping =================================================== /arch/arm/boot/compressed/misc.c static void putNum(uint32_t num) ... =================================================== Configuration related =================================================== /arch/arm/Makefile machine-$(CONFIG_ARCH_HELIOSX) += heliosx /arch/arm/boot/dts/Makefile dtb-$(CONFIG_ARCH_HELIOSX) += heliosx.dtb /arch/arm/tools/mach-types heliosx MACH_HELIOSX HELIOSX 7777 =================================================== device tree configuration memory interrupt controller timer (interrupts = <8>) UART, serial port (interrupts = <2>;) =================================================== /arch/arm/boot/dts/heliosx.dts memory{ device_type = "memory"; reg = <0x08000000 0x04000000="">; }; soc { compatible = "simple-bus"; /* mapping to platform bus*/ #address-cells = <1>; #size-cells = <1>; ranges; intc_legacy: intc@D0081000 { compatible = "arm,heliosx-intc-legacy"; interrupt-controller; #interrupt-cells = <1>; // other peripherals, register memory map and physical interrupt number ... timer@D0081200 { compatible = "arm,heliosx-timer"; reg = <0xd0081200 0x100="">; interrupts = <8>; clock-names = "heliosx-timer"; }; serial0: serial@D000A000 { compatible = "arm,heliosx-uart"; reg = <0xd000a000 0x1000="">; interrupts = <2>; /* 2, 3 is combined */ }; ... =================================================== configuration for compile =================================================== /arch/arm/configs/heliosx_deconfig various configuration for compile =================================================== UART device driver for boot UART output code, =================================================== /arch/arm/include/debug/heliosx.S /* * addruart_current will check if MMU is enabled and decide * which address to use, virtual or physical */ .macro addruart, rp, rv, tmp ldr \rp, =UART_PADDR @ physical ldr \rv, =UART_VADDR @ virtual .endm ... DT_MACHINE_START(HELIOSX, "HeliosX") .map_io = hx_map_io, MACHINE_END =================================================== Add some debug output =================================================== /arch/arm/kernel/atag_parse.c early_print ... /arch/arm/kernel/setup.c setup_arch ... =================================================== Add a new machine supporting files Kconfig for compile feature select Makefile to add heliosx.c Heliosx.c to setup machine =================================================== /arch/arm/mach-heliosx/* static const char * const hx_dt_match[] __initconst = { "heliosx", NULL, }; static struct map_desc hx_io_desc[] __initdata = { { .virtual = (unsigned long) HX_REGS_UART_VIRT_BASE, .pfn = __phys_to_pfn(HX_REGS_UART_PHYS_BASE), .length = HX_REGS_UART_SIZE, .type = MT_DEVICE, }, }; ... DT_MACHINE_START(HELIOSX, "HeliosX") .map_io = hx_map_io, MACHINE_END ... =================================================== Add debugging info for MMU =================================================== /arch/arm/mm/mmu.c =================================================== Add new machine info =================================================== /arch/arm/tools/mach-types heliosx MACH_HELIOSX HELIOSX ... =================================================== Add new machine info =================================================== /arch/arm/tools/mach-types =================================================== Some configuration file =================================================== /arch/arm/Kconfig /arch/arm/Kconfig.debug /arch/arm/Makefile config HELIOSX_DRAM_REGION_BASE hex "Region base" help Region base ... =================================================== Clock source(timer) driver implement functions of clock source framework hx_timer_set_next_event, kick of next timer to raise interrupt based on "next" timer =================================================== /drivers/clocksource/heliosx_timer.c static void __init hx_timer_init(struct device_node *node) setup_irq(irq, &hx_timer_irq) ... static irqreturn_t hx_timer_interrupt(int irq, void *dev_id) ... =================================================== Interrupt controller handle_one_hxleg, read status register to find out which hardware interrupt is raised. calls irq_create_mapping to create HW/SW irq mapping for 16 irq =================================================== /drivers/irqchip/irq-heliosx.c static struct irq_domain_ops hxleg_irqdomain_ops = { .map = hxleg_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; static void __exception_irq_entry hxleg_handle_irq(struct pt_regs *regs) { int handled; do { handled = handle_one_hxleg(regs); } while (handled); } static void __init hxleg_register(struct device_node *node) { .... v->domain = irq_domain_add_simple(node, irqsize, 0, &hxleg_irqdomain_ops, v); for (i = 0; i < irqsize; i++) { irq_create_mapping(v->domain, i); } ... } ... =================================================== UART driver =================================================== /drivers/tty/serial/heliosx_uart.c static void hx_uart_do_rx(struct uart_port *port) static irqreturn_t hx_uart_interrupt(int irq, void *dev_id) ... =================================================== HeliosX Port (What is that? I forgot) =================================================== /include/uapi/linux/serial_core.h /* HeliosX Port */ #define PORT_HELIOSX 113 ... 2>0xd000a000>8>0xd0081200>1>1>1>0x08000000>2>8>