From 99648958668d3a33ee57974479b36201fe303f34 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 20 Apr 2018 10:35:35 +0200 Subject: bsps: Move startup files to bsps Adjust build support files to new directory layout. This patch is a part of the BSP source reorganization. Update #3285. --- bsps/m68k/gen68360/start/alloc360.c | 94 ++++ bsps/m68k/gen68360/start/bsp_specs | 9 + bsps/m68k/gen68360/start/init68360.c | 846 ++++++++++++++++++++++++++++++++ bsps/m68k/gen68360/start/linkcmds | 209 ++++++++ bsps/m68k/gen68360/start/linkcmds.bootp | 171 +++++++ bsps/m68k/gen68360/start/linkcmds.prom | 169 +++++++ 6 files changed, 1498 insertions(+) create mode 100644 bsps/m68k/gen68360/start/alloc360.c create mode 100644 bsps/m68k/gen68360/start/bsp_specs create mode 100644 bsps/m68k/gen68360/start/init68360.c create mode 100644 bsps/m68k/gen68360/start/linkcmds create mode 100644 bsps/m68k/gen68360/start/linkcmds.bootp create mode 100644 bsps/m68k/gen68360/start/linkcmds.prom (limited to 'bsps/m68k/gen68360') diff --git a/bsps/m68k/gen68360/start/alloc360.c b/bsps/m68k/gen68360/start/alloc360.c new file mode 100644 index 0000000000..53f90876e4 --- /dev/null +++ b/bsps/m68k/gen68360/start/alloc360.c @@ -0,0 +1,94 @@ +/* + * MC68360 buffer descriptor allocation routines + * + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +#include +#include +#include +#include + +/* + * Allocation order: + * - Dual-Port RAM section 1 + * - Dual-Port RAM section 3 + * - Dual-Port RAM section 0 + * - Dual-Port RAM section 2 + */ +static struct { + uint8_t *base; + uint32_t size; + uint32_t used; +} bdregions[] = { + { (uint8_t *)&m360.dpram1[0], sizeof m360.dpram1, 0 }, + { (uint8_t *)&m360.dpram3[0], sizeof m360.dpram3, 0 }, + { (uint8_t *)&m360.dpram0[0], sizeof m360.dpram0, 0 }, + { (uint8_t *)&m360.dpram2[0], sizeof m360.dpram2, 0 }, +}; + +/* + * Send a command to the CPM RISC processer + */ +void * +M360AllocateBufferDescriptors (int count) +{ + unsigned int i; + ISR_Level level; + void *bdp = NULL; + unsigned int want = count * sizeof(m360BufferDescriptor_t); + + /* + * Running with interrupts disabled is usually considered bad + * form, but this routine is probably being run as part of an + * initialization sequence so the effect shouldn't be too severe. + */ + _ISR_Local_disable (level); + for (i = 0 ; i < sizeof(bdregions) / sizeof(bdregions[0]) ; i++) { + /* + * Verify that the region exists. + * This test is necessary since some chips have + * less dual-port RAM. + */ + if (bdregions[i].used == 0) { + volatile uint8_t *cp = bdregions[i].base; + *cp = 0xAA; + if (*cp != 0xAA) { + bdregions[i].used = bdregions[i].size; + continue; + } + *cp = 0x55; + if (*cp != 0x55) { + bdregions[i].used = bdregions[i].size; + continue; + } + *cp = 0x0; + } + if (bdregions[i].size - bdregions[i].used >= want) { + bdp = bdregions[i].base + bdregions[i].used; + bdregions[i].used += want; + break; + } + } + _ISR_Local_enable (level); + if (bdp == NULL) + rtems_panic ("Can't allocate %d buffer descriptor(s).\n", count); + return bdp; +} + +void * +M360AllocateRiscTimers (int count) +{ + /* + * Convert the count to the number of buffer descriptors + * of equal or larger size. This ensures that all buffer + * descriptors are allocated with appropriate alignment. + */ + return M360AllocateBufferDescriptors (((count * 4) + + sizeof(m360BufferDescriptor_t) - 1) / + sizeof(m360BufferDescriptor_t)); +} diff --git a/bsps/m68k/gen68360/start/bsp_specs b/bsps/m68k/gen68360/start/bsp_specs new file mode 100644 index 0000000000..87638cc027 --- /dev/null +++ b/bsps/m68k/gen68360/start/bsp_specs @@ -0,0 +1,9 @@ +%rename endfile old_endfile +%rename startfile old_startfile + +*startfile: +%{!qrtems: %(old_startfile)} \ +%{!nostdlib: %{qrtems: crti.o%s crtbegin.o%s}} + +*endfile: +%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s crtn.o%s} diff --git a/bsps/m68k/gen68360/start/init68360.c b/bsps/m68k/gen68360/start/init68360.c new file mode 100644 index 0000000000..67fed27a3b --- /dev/null +++ b/bsps/m68k/gen68360/start/init68360.c @@ -0,0 +1,846 @@ +/* + * MC68360 support routines + */ + +/* + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +#include +#include + +extern void _CopyDataClearBSSAndStart (unsigned long ramSize); +extern void *RamBase; +extern void *_RomBase; /* From linkcmds */ + +/* + * Declare the m360 structure here for the benefit of the debugger + */ + +volatile m360_t m360; + +/* + * Send a command to the CPM RISC processer + */ + +void M360ExecuteRISC(uint16_t command) +{ + uint16_t sr; + + m68k_disable_interrupts (sr); + while (m360.cr & M360_CR_FLG) + continue; + m360.cr = command | M360_CR_FLG; + m68k_enable_interrupts (sr); +} + +/* + * Initialize MC68360 + */ +void _Init68360 (void) +{ + int i; + rtems_isr_entry *vbr; + unsigned long ramSize; + +#if (defined (__mc68040__)) + volatile unsigned long *RamBase_p; + + RamBase_p = (volatile unsigned long *)&RamBase; + + /* + ******************************************* + * Motorola 68040 and companion-mode 68360 * + ******************************************* + */ + + /* + * Step 6: Is this a power-up reset? + * For now we just ignore this and do *all* the steps + * Someday we might want to: + * if (Hard, Loss of Clock, Power-up) + * Do all steps + * else if (Double bus fault, watchdog or soft reset) + * Skip to step 12 + * else (must be a reset command) + * Skip to step 14 + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external 25 MHz oscillator. + */ + m360.clkocr = 0x83; /* No more writes, full-power CLKO2 */ + m360.pllcr = 0xD000; /* PLL, no writes, no prescale, + no LPSTOP slowdown, PLL X1 */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * Next-to-slowest watchdog timeout (21 seconds with 25 MHz oscillator) + * Enable double bus fault monitor + * Enable bus monitor for external cycles + * 1024 clocks for external timeout + */ + m360.sypcr = 0xEC; + + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT standard M68000 family interrupt level encoding + * CF1MODE=10 (BCLRO* output) + * No RAS1* double drive + * A31 - A28 + * AMUX output + * CAS2* - CAS3* + * CAS0* - CAS1* + * CS7* + * AVEC* + */ + m360.pepar = 0x3440; + + /* + * Step 11: Remap Chip Select 0 (CS0*), set up GMR + */ + /* + * 512 addresses per DRAM page (256K DRAM chips) + * 70 nsec DRAM + * 180 nsec ROM (3 wait states) + */ + m360.gmr = M360_GMR_RCNT(23) | M360_GMR_RFEN | + M360_GMR_RCYC(0) | M360_GMR_PGS(1) | + M360_GMR_DPS_32BIT | M360_GMR_NCS | + M360_GMR_TSS40; + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(3) | M360_MEMC_OR_1MB | + M360_MEMC_OR_32BIT; + + /* + * Step 12: Initialize the system RAM + */ + /* + * Set up option/base registers + * 1M DRAM + * 70 nsec DRAM + * Enable burst mode + * No parity checking + * Wait for chips to power up + * Perform 8 read cycles + */ + ramSize = 1 * 1024 * 1024; + m360.memc[1].or = M360_MEMC_OR_TCYC(0) | + M360_MEMC_OR_1MB | + M360_MEMC_OR_DRAM; + m360.memc[1].br = (unsigned long)&RamBase | + M360_MEMC_BR_BACK40 | + M360_MEMC_BR_V; + for (i = 0; i < 50000; i++) + continue; + for (i = 0; i < 8; ++i) { + unsigned long rambase_value; + rambase_value = *RamBase_p; + (void) rambase_value; /* avoid set but not used warning */ + } + + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Enable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Bus request MC68040 Arbitration ID 3 + * Bus asynchronous timing mode (work around bug in Rev. B) + * Arbitration asynchronous timing mode + * Disable timers during FREEZE + * Disable bus monitor during FREEZE + * BCLRO* arbitration level 3 + * No show cycles + * User/supervisor access + * Bus clear in arbitration ID level 3 + * SIM60 interrupt sources higher priority than CPM + */ + m360.mcr = 0x6000EC3F; + +#elif (defined (M68360_ATLAS_HSB)) + /* + ****************************************** + * Standalone Motorola 68360 -- ATLAS HSB * + ****************************************** + */ + + /* + * Step 6: Is this a power-up reset? + * For now we just ignore this and do *all* the steps + * Someday we might want to: + * if (Hard, Loss of Clock, Power-up) + * Do all steps + * else if (Double bus fault, watchdog or soft reset) + * Skip to step 12 + * else (must be a CPU32+ reset command) + * Skip to step 14 + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external 25 MHz oscillator. + */ + m360.clkocr = 0x8F; /* No more writes, no clock outputs */ + m360.pllcr = 0xD000; /* PLL, no writes, no prescale, + no LPSTOP slowdown, PLL X1 */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * Next-to-slowest watchdog timeout (21 seconds with 25 MHz oscillator) + * Enable double bus fault monitor + * Enable bus monitor for external cycles + * 1024 clocks for external timeout + */ + m360.sypcr = 0xEC; + + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT not used (CPU32+ mode) + * CF1MODE=00 (CONFIG1 input) + * RAS1* double drive + * WE0* - WE3* + * OE* output + * CAS2* - CAS3* + * CAS0* - CAS1* + * CS7* + * AVEC* + * HARDWARE: + * Change if you are using a different memory configuration + * (static RAM, external address multiplexing, etc). + */ + m360.pepar = 0x0180; + + /* + * Step 11: Remap Chip Select 0 (CS0*), set up GMR + */ + m360.gmr = M360_GMR_RCNT(12) | M360_GMR_RFEN | + M360_GMR_RCYC(0) | M360_GMR_PGS(1) | + M360_GMR_DPS_32BIT | M360_GMR_DWQ | + M360_GMR_GAMX; + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(3) | M360_MEMC_OR_1MB | + M360_MEMC_OR_8BIT; + + /* + * Step 12: Initialize the system RAM + */ + ramSize = 2 * 1024 * 1024; + /* first bank 1MByte DRAM */ + m360.memc[1].or = M360_MEMC_OR_TCYC(2) | M360_MEMC_OR_1MB | + M360_MEMC_OR_PGME | M360_MEMC_OR_DRAM; + m360.memc[1].br = (unsigned long)&RamBase | M360_MEMC_BR_V; + + /* second bank 1MByte DRAM */ + m360.memc[2].or = M360_MEMC_OR_TCYC(2) | M360_MEMC_OR_1MB | + M360_MEMC_OR_PGME | M360_MEMC_OR_DRAM; + m360.memc[2].br = ((unsigned long)&RamBase + 0x100000) | + M360_MEMC_BR_V; + + /* flash rom socket U6 on CS5 */ + m360.memc[5].br = (unsigned long)ATLASHSB_ROM_U6 | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[5].or = M360_MEMC_OR_WAITS(2) | M360_MEMC_OR_512KB | + M360_MEMC_OR_8BIT; + + /* CSRs on CS7 */ + m360.memc[7].or = M360_MEMC_OR_TCYC(4) | M360_MEMC_OR_64KB | + M360_MEMC_OR_8BIT; + m360.memc[7].br = ATLASHSB_ESR | 0x01; + for (i = 0; i < 50000; i++) + continue; + for (i = 0; i < 8; ++i) + *((volatile unsigned long *)(unsigned long)&RamBase); + + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Enable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Disable timers during FREEZE + * Enable bus monitor during FREEZE + * BCLRO* arbitration level 3 + */ + +#elif defined(PGH360) + /* + * Step 6: Is this a power-up reset? + * For now we just ignore this and do *all* the steps + * Someday we might want to: + * if (Hard, Loss of Clock, Power-up) + * Do all steps + * else if (Double bus fault, watchdog or soft reset) + * Skip to step 12 + * else (must be a CPU32+ reset command) + * Skip to step 14 + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external 25 MHz oscillator. + */ + m360.clkocr = 0x8e; /* No more writes, CLKO1=1/3, CLKO2=off */ + /* + * adjust crystal to average between 4.19 MHz and 4.00 MHz + * reprogram pll + */ + m360.pllcr = 0xA000+(24576000/((4000000+4194304)/2/128))-1; + /* LPSTOP slowdown, PLL /128*??? */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * 128 sec. watchdog timeout + * Enable double bus fault monitor + * Enable bus monitor external + * 128 clocks for external timeout + */ + m360.sypcr = 0xEF; + /* + * also initialize the SWP bit in PITR to 1 + */ + m360.pitr |= 0x0200; + /* + * and trigger SWSR twice to ensure, that interval starts right now + */ + m360.swsr = 0x55; + m360.swsr = 0xAA; + m360.swsr = 0x55; + m360.swsr = 0xAA; + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT not used (CPU32+ mode) + * CF1MODE=00 (CONFIG1 input) + * IPIPE1 + * WE0-3 + * OE* output + * CAS2* / CAS3* + * CAS0* / CAS1* + * CS7* + * AVEC* + * HARDWARE: + * Change if you are using a different memory configuration + * (static RAM, external address multiplexing, etc). + */ + m360.pepar = 0x0080; + /* + * Step 11: Remap Chip Select 0 (CS0*), set up GMR + * no DRAM support + * HARDWARE: + * Change if you are using a different memory configuration + */ + m360.gmr = M360_GMR_RCNT(23) | M360_GMR_RFEN | M360_GMR_RCYC(0) | + M360_GMR_PGS(6) | M360_GMR_DPS_32BIT | M360_GMR_DWQ | + M360_GMR_GAMX; + + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(3) | M360_MEMC_OR_512KB | + M360_MEMC_OR_8BIT; + + /* + * Step 12: Initialize the system RAM + * Set up option/base registers + * 16 MB DRAM + * 1 wait state + * HARDWARE: + * Change if you are using a different memory configuration + * NOTE: no Page mode possible for EDO RAMs (?) + */ + ramSize = 16 * 1024 * 1024; + m360.memc[7].or = M360_MEMC_OR_TCYC(1) | M360_MEMC_OR_16MB | + M360_MEMC_OR_FCMC(0) | /* M360_MEMC_OR_PGME | */ + M360_MEMC_OR_32BIT | M360_MEMC_OR_DRAM; + m360.memc[7].br = (unsigned long)&RamBase | M360_MEMC_BR_V; + + /* + * FIXME: here we should wait for 8 refresh cycles... + */ + /* + * Step 12a: test the ram, if wanted + * FIXME: when do we call this? + * -> only during firmware execution + * -> perform intesive test only on request + * -> ensure, that results are stored properly + */ +#if 0 /* FIXME: activate RAM tests again */ + { + void *ram_base, *ram_end, *code_loc; + extern char ramtest_start,ramtest_end; + ram_base = &ramtest_start; + ram_end = &ramtest_end; + code_loc = (void *)ramtest_exec; + if ((ram_base < ram_end) && + !((ram_base <= code_loc) && (code_loc < ram_end))) { + ramtest_exec(ram_base,ram_end); + } + } +#endif + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Disable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Disable timers during FREEZE + * Enable bus monitor during FREEZE + * BCLRO* arbitration level 3 + * No show cycles + * User/supervisor access + * Bus clear interupt service level 7 + * SIM60 interrupt sources higher priority than CPM + */ + m360.mcr = 0x4C7F; + +#elif (defined (GEN68360_WITH_SRAM)) + /* + *************************************************** + * Generic Standalone Motorola 68360 * + * As described in MC68360 User's Manual * + * But uses SRAM instead of DRAM * + * CS0* - 512kx8 flash memory * + * CS1* - 512kx32 static RAM * + * CS2* - 512kx32 static RAM * + *************************************************** + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external oscillator which + * oscillates at the system clock rate. + */ + m360.clkocr = 0x8F; /* No more writes, no clock outputs */ + m360.pllcr = 0xD000; /* PLL, no writes, no prescale, + no LPSTOP slowdown, PLL X1 */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * Next-to-slowest watchdog timeout (21 seconds with 25 MHz oscillator) + * Enable double bus fault monitor + * Enable bus monitor for external cycles + * 1024 clocks for external timeout + */ + m360.sypcr = 0xEC; + + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT not used (CPU32+ mode) + * CF1MODE=00 (CONFIG1 input) + * IPIPE1* + * WE0* - WE3* + * OE* output + * CAS2* - CAS3* + * CAS0* - CAS1* + * CS7* + * AVEC* + * HARDWARE: + * Change if you are using a different memory configuration + * (static RAM, external address multiplexing, etc). + */ + m360.pepar = 0x0080; + + /* + * Step 11: Set up GMR + * + */ + m360.gmr = 0x0; + + /* + * Step 11a: Remap 512Kx8 flash memory on CS0* + * 2 wait states + * Make it read-only for now + */ + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(2) | M360_MEMC_OR_512KB | + M360_MEMC_OR_8BIT; + /* + * Step 12: Set up main memory + * 512Kx32 SRAM on CS1* + * 512Kx32 SRAM on CS2* + * 0 wait states + */ + ramSize = 4 * 1024 * 1024; + m360.memc[1].br = (unsigned long)&RamBase | M360_MEMC_BR_V; + m360.memc[1].or = M360_MEMC_OR_WAITS(0) | M360_MEMC_OR_2MB | + M360_MEMC_OR_32BIT; + m360.memc[2].br = ((unsigned long)&RamBase + 0x200000) | M360_MEMC_BR_V; + m360.memc[2].or = M360_MEMC_OR_WAITS(0) | M360_MEMC_OR_2MB | + M360_MEMC_OR_32BIT; + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Enable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Disable timers during FREEZE + * Enable bus monitor during FREEZE + * BCLRO* arbitration level 3 + * No show cycles + * User/supervisor access + * Bus clear interrupt service level 7 + * SIM60 interrupt sources higher priority than CPM + */ + m360.mcr = 0x4C7F; + +#else + volatile unsigned long *RamBase_p; + + RamBase_p = (volatile unsigned long *)&RamBase; + /* + *************************************************** + * Generic Standalone Motorola 68360 * + * As described in MC68360 User's Manual * + * Atlas ACE360 * + *************************************************** + */ + + /* + * Step 6: Is this a power-up reset? + * For now we just ignore this and do *all* the steps + * Someday we might want to: + * if (Hard, Loss of Clock, Power-up) + * Do all steps + * else if (Double bus fault, watchdog or soft reset) + * Skip to step 12 + * else (must be a CPU32+ reset command) + * Skip to step 14 + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external 25 MHz oscillator. + */ + m360.clkocr = 0x8F; /* No more writes, no clock outputs */ + m360.pllcr = 0xD000; /* PLL, no writes, no prescale, + no LPSTOP slowdown, PLL X1 */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * Next-to-slowest watchdog timeout (21 seconds with 25 MHz oscillator) + * Enable double bus fault monitor + * Enable bus monitor for external cycles + * 1024 clocks for external timeout + */ + m360.sypcr = 0xEC; + + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT not used (CPU32+ mode) + * CF1MODE=00 (CONFIG1 input) + * RAS1* double drive + * WE0* - WE3* + * OE* output + * CAS2* - CAS3* + * CAS0* - CAS1* + * CS7* + * AVEC* + * HARDWARE: + * Change if you are using a different memory configuration + * (static RAM, external address multiplexing, etc). + */ + m360.pepar = 0x0180; + + /* + * Step 11: Remap Chip Select 0 (CS0*), set up GMR + * 32-bit DRAM + * Internal DRAM address multiplexing + * 60 nsec DRAM + * 180 nsec ROM (3 wait states) + * 15.36 usec DRAM refresh interval + * The DRAM page size selection is not modified since this + * startup code may be running in a bootstrap PROM or in + * a program downloaded by the bootstrap PROM. + */ + m360.gmr = (m360.gmr & 0x001C0000) | M360_GMR_RCNT(23) | + M360_GMR_RFEN | M360_GMR_RCYC(0) | + M360_GMR_DPS_32BIT | M360_GMR_NCS | + M360_GMR_GAMX; + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(3) | M360_MEMC_OR_1MB | + M360_MEMC_OR_8BIT; + + /* + * Step 12: Initialize the system RAM + * Do this only if the DRAM has not already been set up + */ + if ((m360.memc[1].br & M360_MEMC_BR_V) == 0) { + /* + * Set up GMR DRAM page size, option and base registers + * Assume 16Mbytes of DRAM + * 60 nsec DRAM + */ + m360.gmr = (m360.gmr & ~0x001C0000) | M360_GMR_PGS(5); + m360.memc[1].or = M360_MEMC_OR_TCYC(0) | + M360_MEMC_OR_16MB | + M360_MEMC_OR_DRAM; + m360.memc[1].br = (unsigned long)&RamBase | M360_MEMC_BR_V; + + /* + * Wait for chips to power up + * Perform 8 read cycles + */ + for (i = 0; i < 50000; i++) + continue; + for (i = 0; i < 8; ++i) + *RamBase_p; + + /* + * Determine memory size (1, 4, or 16 Mbytes) + * Set GMR DRAM page size appropriately. + * The OR is left at 16 Mbytes. The bootstrap PROM places its + * .data and .bss segments at the top of the 16 Mbyte space. + * A 1 Mbyte or 4 Mbyte DRAM will show up several times in + * the memory map, but will work with the same bootstrap PROM. + */ + *(volatile char *)&RamBase = 0; + *((volatile char *)&RamBase+0x00C01800) = 1; + if (*(volatile char *)&RamBase) { + m360.gmr = (m360.gmr & ~0x001C0000) | M360_GMR_PGS(1); + } + else { + *((volatile char *)&RamBase+0x00801000) = 1; + if (*(volatile char *)&RamBase) { + m360.gmr = (m360.gmr & ~0x001C0000) | M360_GMR_PGS(3); + } + } + + /* + * Enable parity checking + */ + m360.memc[1].br |= M360_MEMC_BR_PAREN; + } + switch (m360.gmr & 0x001C0000) { + default: ramSize = 4 * 1024 * 1024; break; + case M360_GMR_PGS(1): ramSize = 1 * 1024 * 1024; break; + case M360_GMR_PGS(3): ramSize = 4 * 1024 * 1024; break; + case M360_GMR_PGS(5): ramSize = 16 * 1024 * 1024; break; + } + + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Enable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Disable timers during FREEZE + * Enable bus monitor during FREEZE + * BCLRO* arbitration level 3 + * No show cycles + * User/supervisor access + * Bus clear interrupt service level 7 + * SIM60 interrupt sources higher priority than CPM + */ + m360.mcr = 0x4C7F; +#endif + + /* + * Copy data, clear BSS, switch stacks and call main() + * Must pass ramSize as argument since the data/bss segment + * may be overwritten. + */ + _CopyDataClearBSSAndStart (ramSize); +} diff --git a/bsps/m68k/gen68360/start/linkcmds b/bsps/m68k/gen68360/start/linkcmds new file mode 100644 index 0000000000..4ffc8bb57a --- /dev/null +++ b/bsps/m68k/gen68360/start/linkcmds @@ -0,0 +1,209 @@ +/* + * This file contains GNU linker directives for a generic MC68360 board. + * Variations in memory size and allocation can be made by + * overriding some values with linker command-line arguments. + * + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +/* + * Declare some sizes. + * A heap size of 0 means `use all available memory for the heap'. + */ +RamBase = DEFINED(RamBase) ? RamBase : 0x0; +RamSize = DEFINED(RamSize) ? RamSize : 64M; +HeapSize = DEFINED(HeapSize) ? HeapSize : 0x0; +_StackSize = DEFINED(_StackSize) ? _StackSize : 0x1000; + +/* + * Declare on-board memory. + */ +MEMORY { + ram : ORIGIN = 0x00000000, LENGTH = 64M + rom : ORIGIN = 0x0F000000, LENGTH = 1M + dpram : ORIGIN = 0x0E000000, LENGTH = 8k +} + +ENTRY(start) +STARTUP(start.o) + +/* + * Load objects + */ +SECTIONS { + /* + * Boot PROM + */ + rom : { + _RomBase = .; + } >rom + + /* + * Dynamic RAM + */ + ram : { + RamBase = .; + } >ram + + /* + * Text, data and bss segments + */ + .text : { + *(.text*) + + /* + * C++ constructors/destructors + */ + *(.gnu.linkonce.t.*) + + /* + * Initialization and finalization code. + */ + PROVIDE (_init = .); + *crti.o(.init) + *(.init) + *crtn.o(.init) + PROVIDE (_fini = .); + *crti.o(.fini) + *(.fini) + *crtn.o(.fini) + + /* + * Special FreeBSD sysctl sections. + */ + . = ALIGN (16); + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = ABSOLUTE(.); + *(set_domain_*); + *(set_pseudo_*); + + /* + * C++ constructors/destructors + */ + . = ALIGN (16); + *crtbegin.o(.ctors) + *(.ctors) + *crtend.o(.ctors) + *crtbegin.o(.dtors) + *(.dtors) + *crtend.o(.dtors) + + /* + * Exception frame info + */ + . = ALIGN (16); + *(.eh_frame) + + /* + * Read-only data + */ + . = ALIGN (16); + _rodata_start = . ; + *(.rodata*) + KEEP (*(SORT(.rtemsroset.*))) + *(.gnu.linkonce.r*) + + . = ALIGN (16); + PROVIDE (etext = .); + } >ram + + .tdata : { + _TLS_Data_begin = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + _TLS_Data_end = .; + } >ram + + .tbss : { + _TLS_BSS_begin = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + _TLS_BSS_end = .; + } >ram + + _TLS_Data_size = _TLS_Data_end - _TLS_Data_begin; + _TLS_Data_begin = _TLS_Data_size != 0 ? _TLS_Data_begin : _TLS_BSS_begin; + _TLS_Data_end = _TLS_Data_size != 0 ? _TLS_Data_end : _TLS_BSS_begin; + _TLS_BSS_size = _TLS_BSS_end - _TLS_BSS_begin; + _TLS_Size = _TLS_BSS_end - _TLS_Data_begin; + _TLS_Alignment = MAX (ALIGNOF (.tdata), ALIGNOF (.tbss)); + + .data : { + _copy_start = .; + *(.data*) + KEEP (*(SORT(.rtemsrwset.*))) + *(.gnu.linkonce.d*) + *(.gcc_except_table*) + *(.jcr) + . = ALIGN (16); + PROVIDE (edata = .); + _copy_end = .; + } >ram + .bss : { + M68Kvec = .; + . += (256 * 4); + _clear_start = .; + *(.dynbss) + *(.bss* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (16); + PROVIDE (end = .); + + . += _StackSize; + . = ALIGN (16); + _stack_init = .; + _clear_end = .; + + WorkAreaBase = .; + } >ram + + /* + * On-chip memory/peripherals + */ + dpram : { + m360 = .; + . += (8 * 1024); + } >dpram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/bsps/m68k/gen68360/start/linkcmds.bootp b/bsps/m68k/gen68360/start/linkcmds.bootp new file mode 100644 index 0000000000..ccd08a14a2 --- /dev/null +++ b/bsps/m68k/gen68360/start/linkcmds.bootp @@ -0,0 +1,171 @@ +/* + * This file contains GNU linker directives for a generic MC68360 board. + * Variations in memory size and allocation can be made by + * overriding some values with linker command-line arguments. + * + * These linker directives are for producing a bootstrap PROM version. + * The data segment is placed at the end of the text segment in the PROM. + * The start-up code takes care of copying this region to RAM. + * + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +/* + * Declare some sizes. + * A heap size of 0 means `use all available memory for the heap'. + */ +RamBase = DEFINED(RamBase) ? RamBase : 0x0; +RamSize = DEFINED(RamSize) ? RamSize : 64M; +HeapSize = DEFINED(HeapSize) ? HeapSize : 0x0; +_StackSize = DEFINED(_StackSize) ? _StackSize : 0x1000; + +/* + * Declare on-board memory. + */ +MEMORY { + ram : ORIGIN = 0x00000000, LENGTH = 64M + myram : ORIGIN = 16M-400k, LENGTH = 400k + rom : ORIGIN = 0x0F000000, LENGTH = 1M + dpram : ORIGIN = 0x0E000000, LENGTH = 8k +} + +/* + * Load objects + */ +SECTIONS { + /* + * Boot PROM + */ + rom : { + _RomBase = .; + } >rom + + /* + * Dynamic RAM + */ + ram : { + RamBase = .; + } >ram + + /* + * Text, data and bss segments + */ + .text : AT(0x0) { + *(.text*) + + /* + * C++ constructors/destructors + */ + *(.gnu.linkonce.t.*) + + /* + * Initialization and finalization code. + */ + PROVIDE (_init = .); + *crti.o(.init) + *(.init) + *crtn.o(.init) + PROVIDE (_fini = .); + *crti.o(.fini) + *(.fini) + *crtn.o(.fini) + + /* + * Special FreeBSD sysctl sections. + */ + . = ALIGN (16); + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = ABSOLUTE(.); + *(set_domain_*); + *(set_pseudo_*); + + /* + * C++ constructors/destructors + */ + . = ALIGN (16); + *crtbegin.o(.ctors) + *(.ctors) + *crtend.o(.ctors) + *crtbegin.o(.dtors) + *(.dtors) + *crtend.o(.dtors) + + /* + * Exception frame info + */ + . = ALIGN (16); + *(.eh_frame) + + /* + * Read-only data + */ + . = ALIGN (16); + _rodata_start = . ; + *(.rodata*) + KEEP (*(SORT(.rtemsroset.*))) + *(.gnu.linkonce.r*) + + . = ALIGN (16); + PROVIDE (etext = .); + } >rom + + .tdata : { + _TLS_Data_begin = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + _TLS_Data_end = .; + } >rom + + .tbss : { + _TLS_BSS_begin = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + _TLS_BSS_end = .; + } >rom + + _TLS_Data_size = _TLS_Data_end - _TLS_Data_begin; + _TLS_Data_begin = _TLS_Data_size != 0 ? _TLS_Data_begin : _TLS_BSS_begin; + _TLS_Data_end = _TLS_Data_size != 0 ? _TLS_Data_end : _TLS_BSS_begin; + _TLS_BSS_size = _TLS_BSS_end - _TLS_BSS_begin; + _TLS_Size = _TLS_BSS_end - _TLS_Data_begin; + _TLS_Alignment = MAX (ALIGNOF (.tdata), ALIGNOF (.tbss)); + + .data : AT(SIZEOF(.text)) { + _copy_start = .; + *(.data) + KEEP (*(SORT(.rtemsrwset.*))) + *(.gnu.linkonce.d*) + *(.jcr) + *(.gcc_except_table*) + . = ALIGN (16); + PROVIDE (edata = .); + _copy_end = .; + } >myram + .bss : { + M68Kvec = .; + . += (256 * 4); + _clear_start = .; + *(.dynbss) + *(.bss* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (16); + PROVIDE (end = .); + + . += _StackSize; + . = ALIGN (16); + _stack_init = .; + _clear_end = .; + + WorkAreaBase = .; + } >myram + + /* + * On-chip memory/peripherals + */ + dpram : { + m360 = .; + . += (8 * 1024); + } >dpram +} diff --git a/bsps/m68k/gen68360/start/linkcmds.prom b/bsps/m68k/gen68360/start/linkcmds.prom new file mode 100644 index 0000000000..777700e6a1 --- /dev/null +++ b/bsps/m68k/gen68360/start/linkcmds.prom @@ -0,0 +1,169 @@ +/* + * This file contains GNU linker directives for a generic MC68360 board. + * Variations in memory size and allocation can be made by + * overriding some values with linker command-line arguments. + * + * These linker directives are for producing a PROM version. + * The data segment is placed at the end of the text segment in the PROM. + * The start-up code takes care of copying this region to RAM. + * + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +/* + * Declare some sizes. + * A heap size of 0 means `use all available memory for the heap'. + */ +RamBase = DEFINED(RamBase) ? RamBase : 0x0; +RamSize = DEFINED(RamSize) ? RamSize : 64M; +HeapSize = DEFINED(HeapSize) ? HeapSize : 0x0; +_StackSize = DEFINED(_StackSize) ? _StackSize : 0x1000; + +/* + * Declare on-board memory. + */ +MEMORY { + ram : ORIGIN = 0x00000000, LENGTH = 64M + rom : ORIGIN = 0x0F000000, LENGTH = 1M + dpram : ORIGIN = 0x0E000000, LENGTH = 8k +} + +/* + * Load objects + */ +SECTIONS { + /* + * Boot PROM + */ + rom : { + _RomBase = .; + } >rom + + /* + * Dynamic RAM + */ + ram : { + RamBase = .; + } >ram + + /* + * Text, data and bss segments + */ + .text : AT(0x0) { + *(.text*) + + /* + * C++ constructors/destructors + */ + *(.gnu.linkonce.t.*) + + /* + * Initialization and finalization code. + */ + PROVIDE (_init = .); + *crti.o(.init) + *(.init) + *crtn.o(.init) + PROVIDE (_fini = .); + *crti.o(.fini) + *(.fini) + *crtn.o(.fini) + + /* + * Special FreeBSD sysctl sections. + */ + . = ALIGN (16); + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = ABSOLUTE(.); + *(set_domain_*); + *(set_pseudo_*); + + /* + * C++ constructors/destructors + */ + . = ALIGN (16); + *crtbegin.o(.ctors) + *(.ctors) + *crtend.o(.ctors) + *crtbegin.o(.dtors) + *(.dtors) + *crtend.o(.dtors) + + /* + * Exception frame info + */ + . = ALIGN (16); + *(.eh_frame) + + /* + * Read-only data + */ + . = ALIGN (16); + _rodata_start = . ; + *(.rodata*) + KEEP (*(SORT(.rtemsroset.*))) + *(.gnu.linkonce.r*) + + . = ALIGN (16); + PROVIDE (etext = .); + } >rom + + .tdata : { + _TLS_Data_begin = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + _TLS_Data_end = .; + } >rom + + .tbss : { + _TLS_BSS_begin = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + _TLS_BSS_end = .; + } >rom + + _TLS_Data_size = _TLS_Data_end - _TLS_Data_begin; + _TLS_Data_begin = _TLS_Data_size != 0 ? _TLS_Data_begin : _TLS_BSS_begin; + _TLS_Data_end = _TLS_Data_size != 0 ? _TLS_Data_end : _TLS_BSS_begin; + _TLS_BSS_size = _TLS_BSS_end - _TLS_BSS_begin; + _TLS_Size = _TLS_BSS_end - _TLS_Data_begin; + _TLS_Alignment = MAX (ALIGNOF (.tdata), ALIGNOF (.tbss)); + + .data : AT(SIZEOF(.text)) { + _copy_start = .; + *(.data) + KEEP (*(SORT(.rtemsrwset.*))) + *(.gnu.linkonce.d*) + *(.jcr) + *(.gcc_except_table*) + . = ALIGN (16); + PROVIDE (edata = .); + _copy_end = .; + } >ram + .bss : { + M68Kvec = .; + . += (256 * 4); + *(.dynbss) + *(.bss* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (16); + PROVIDE (end = .); + + . += _StackSize; + . = ALIGN (16); + _stack_init = .; + _clear_end = .; + + WorkAreaBase = .; + } >ram + + /* + * On-chip memory/peripherals + */ + dpram : { + m360 = .; + . += (8 * 1024); + } >dpram +} -- cgit v1.2.3