DF-5518 / gpoke.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /* * gpoke.c -- DF-5518 rig helper: plant/read the fake Cherry-View "register" * image in the Memory32Fixed window declared by \_SB.GPO0._CRS. * * Physical window 0x000D0000+0x8000 is ordinary low RAM on this QEMU * (4 GB, pc machine). The window is never excluded from the VM allocator, * so the image is planted at runtime (post-boot, as root) via the 64-bit * direct map rather than relying on boot-time blob contents surviving. * * Pin control register layout (gpio_cherryview.c): * PIN_ADDRESS(x) = 0x4400 + (x/15)*0x400 + (x%15)*8 * CTL0 @ +0, CTL1 @ +4 * Plant for all 59 valid chv_n pins (0..8,15..27,30..41,45..56,60..72): * CTL0 = RXSTATE(bit0) on even pins (GPIOCFG=0: passes check_io_pin for * BOTH RX and TX), CTL1 = 0 (INTCFG=0 passes the TX "interrupt * disabled" check). * FLD0 (59-bit field over the ascending pin table) then reads the magic * pattern computed identically in gen_gpio.py. */ #include <sys/param.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/bus.h> #include <machine/vmparam.h> #include <vm/vm_page.h> #define GPO_BASE 0x000D0000ul #define CHV_PINS 0x4400 #define PIN_INC 0x400 #define PIN_CHUNK 15 static int chv_n_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 }; #define NCHV N(chv_n_pins) #define N(a) (sizeof(a) / sizeof((a)[0])) static uint32_t rd32(vm_paddr_t pa) { return *(volatile uint32_t *)PHYS_TO_DMAP(pa); } static void wr32(vm_paddr_t pa, uint32_t v) { *(volatile uint32_t *)PHYS_TO_DMAP(pa) = v; } static vm_paddr_t pin_ctl0(int pin) { return GPO_BASE + CHV_PINS + (pin / PIN_CHUNK) * PIN_INC + (pin % PIN_CHUNK) * 8; } static void show_pins(const char *tag) { int i; kprintf("gpoke[%s]: CTL0 pins (dmap):", tag); for (i = 0; i < NCHV; i++) kprintf(" %x", rd32(pin_ctl0(chv_n_pins[i])) & 0xFFFF); kprintf("\n"); kprintf("gpoke[%s]: IS=%08x MASK=%08x\n", tag, rd32(GPO_BASE + 0x300), rd32(GPO_BASE + 0x380)); } static void show_both(const char *tag) { int i, bad = 0; kprintf("gpoke[%s]: pin dmap-vs-kernbase CTL0:", tag); for (i = 0; i < NCHV; i++) { uint32_t dm = rd32(pin_ctl0(chv_n_pins[i])); uint32_t kb = *(volatile uint32_t *)(KERNBASE + pin_ctl0(chv_n_pins[i])); if (dm != kb) { bad++; kprintf(" [p%d dmap=%08x kern=%08x]", chv_n_pins[i], dm, kb); } } kprintf(" (%d differ)\n", bad); } static void plant(void) { int i; for (i = 0; i < NCHV; i++) { int pin = chv_n_pins[i]; wr32(pin_ctl0(pin), (pin & 1) ? 0x0 : 0x1); wr32(pin_ctl0(pin) + 4, 0x0); } } static int gpoke_modevent(module_t mod, int type, void *arg) { switch (type) { case MOD_LOAD: show_pins("before"); show_both("before"); plant(); show_pins("after"); show_both("after"); break; case MOD_UNLOAD: break; default: return (EOPNOTSUPP); } return (0); } static moduledata_t gpoke_mod = { "gpoke", gpoke_modevent, NULL }; DECLARE_MODULE(gpoke, gpoke_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_VERSION(gpoke, 1); |