Initial commit - code buildable with rpi

This commit is contained in:
Andrzej Flis
2014-11-27 20:56:49 +01:00
parent 65eccd1f74
commit 191578f645
157 changed files with 11736 additions and 235 deletions

View File

@@ -5,7 +5,7 @@
SUBDIR+= ti1225
. endif # ${MACHINE_ARCH} == "i386"
. if ${MACHINE_ARCH} == "earm"
. if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= i2c
. endif # ${MACHINE_ARCH} == "earm"
.endif # ${MKIMAGEONLY} == "no"

View File

@@ -0,0 +1,7 @@
# Makefile for arch-dependent i2c code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS += omap_i2c.c omap_i2c.h omap_i2c_registers.h

View File

@@ -0,0 +1,876 @@
/*
* This file implements support for i2c on the BeagleBone and BeagleBoard-xM
*/
/* kernel headers */
#include <minix/chardriver.h>
#include <minix/clkconf.h>
#include <minix/drivers.h>
#include <minix/ds.h>
#include <minix/log.h>
#include <minix/mmio.h>
#include <minix/padconf.h>
#include <minix/sysutil.h>
#include <minix/type.h>
#include <minix/board.h>
#include <minix/spin.h>
/* device headers */
#include <minix/i2c.h>
/* system headers */
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
/* usr headers */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* local headers */
#include "omap_i2c.h"
/*
* defines the set of register
*
* Warning: always use the 16-bit variants of read/write/set from mmio.h
* to access these registers. The DM37XX TRM Section 17.6 warns that 32-bit
* accesses can corrupt the register contents.
*/
typedef struct omap_i2c_registers
{
vir_bytes I2C_REVNB_LO; /* AM335X Only */
vir_bytes I2C_REVNB_HI; /* AM335X Only */
vir_bytes I2C_REV; /* DM37XX Only */
vir_bytes I2C_IE; /* DM37XX Only */
vir_bytes I2C_STAT; /* DM37XX Only */
vir_bytes I2C_SYSC;
vir_bytes I2C_IRQSTATUS_RAW; /* AM335X Only */
vir_bytes I2C_IRQSTATUS; /* AM335X Only */
vir_bytes I2C_IRQENABLE_SET; /* AM335X Only */
vir_bytes I2C_IRQENABLE_CLR; /* AM335X Only */
vir_bytes I2C_WE;
vir_bytes I2C_DMARXENABLE_SET; /* AM335X Only */
vir_bytes I2C_DMATXENABLE_SET; /* AM335X Only */
vir_bytes I2C_DMARXENABLE_CLR; /* AM335X Only */
vir_bytes I2C_DMATXENABLE_CLR; /* AM335X Only */
vir_bytes I2C_DMARXWAKE_EN; /* AM335X Only */
vir_bytes I2C_DMATXWAKE_EN; /* AM335X Only */
vir_bytes I2C_SYSS;
vir_bytes I2C_BUF;
vir_bytes I2C_CNT;
vir_bytes I2C_DATA;
vir_bytes I2C_CON;
vir_bytes I2C_OA; /* AM335X Only */
vir_bytes I2C_OA0; /* DM37XX Only */
vir_bytes I2C_SA;
vir_bytes I2C_PSC;
vir_bytes I2C_SCLL;
vir_bytes I2C_SCLH;
vir_bytes I2C_SYSTEST;
vir_bytes I2C_BUFSTAT;
vir_bytes I2C_OA1;
vir_bytes I2C_OA2;
vir_bytes I2C_OA3;
vir_bytes I2C_ACTOA;
vir_bytes I2C_SBLOCK;
} omap_i2c_regs_t;
/* generic definition an i2c bus */
typedef struct omap_i2c_bus
{
enum bus_types
{ AM335X_I2C_BUS, DM37XX_I2C_BUS} bus_type;
phys_bytes mr_base;
phys_bytes mr_size;
vir_bytes mapped_addr;
omap_i2c_regs_t *regs;
uint32_t functional_clock;
uint32_t module_clock;
uint32_t bus_speed;
uint16_t major;
uint16_t minor;
int irq;
int irq_hook_id;
int irq_hook_kernel_id;
} omap_i2c_bus_t;
/* Define the registers for each chip */
static omap_i2c_regs_t am335x_i2c_regs = {
.I2C_REVNB_LO = AM335X_I2C_REVNB_LO,
.I2C_REVNB_HI = AM335X_I2C_REVNB_HI,
.I2C_SYSC = AM335X_I2C_SYSC,
.I2C_IRQSTATUS_RAW = AM335X_I2C_IRQSTATUS_RAW,
.I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS,
.I2C_IRQENABLE_SET = AM335X_I2C_IRQENABLE_SET,
.I2C_IRQENABLE_CLR = AM335X_I2C_IRQENABLE_CLR,
.I2C_WE = AM335X_I2C_WE,
.I2C_DMARXENABLE_SET = AM335X_I2C_DMARXENABLE_SET,
.I2C_DMATXENABLE_SET = AM335X_I2C_DMATXENABLE_SET,
.I2C_DMARXENABLE_CLR = AM335X_I2C_DMARXENABLE_CLR,
.I2C_DMATXENABLE_CLR = AM335X_I2C_DMATXENABLE_CLR,
.I2C_DMARXWAKE_EN = AM335X_I2C_DMARXWAKE_EN,
.I2C_DMATXWAKE_EN = AM335X_I2C_DMATXWAKE_EN,
.I2C_SYSS = AM335X_I2C_SYSS,
.I2C_BUF = AM335X_I2C_BUF,
.I2C_CNT = AM335X_I2C_CNT,
.I2C_DATA = AM335X_I2C_DATA,
.I2C_CON = AM335X_I2C_CON,
.I2C_OA = AM335X_I2C_OA,
.I2C_SA = AM335X_I2C_SA,
.I2C_PSC = AM335X_I2C_PSC,
.I2C_SCLL = AM335X_I2C_SCLL,
.I2C_SCLH = AM335X_I2C_SCLH,
.I2C_SYSTEST = AM335X_I2C_SYSTEST,
.I2C_BUFSTAT = AM335X_I2C_BUFSTAT,
.I2C_OA1 = AM335X_I2C_OA1,
.I2C_OA2 = AM335X_I2C_OA2,
.I2C_OA3 = AM335X_I2C_OA3,
.I2C_ACTOA = AM335X_I2C_ACTOA,
.I2C_SBLOCK = AM335X_I2C_SBLOCK
};
static omap_i2c_regs_t dm37xx_i2c_regs = {
.I2C_REV = DM37XX_I2C_REV,
.I2C_IE = DM37XX_I2C_IE,
.I2C_STAT = DM37XX_I2C_STAT,
.I2C_WE = DM37XX_I2C_WE,
.I2C_SYSS = DM37XX_I2C_SYSS,
.I2C_BUF = DM37XX_I2C_BUF,
.I2C_CNT = DM37XX_I2C_CNT,
.I2C_DATA = DM37XX_I2C_DATA,
.I2C_SYSC = DM37XX_I2C_SYSC,
.I2C_CON = DM37XX_I2C_CON,
.I2C_OA0 = DM37XX_I2C_OA0,
.I2C_SA = DM37XX_I2C_SA,
.I2C_PSC = DM37XX_I2C_PSC,
.I2C_SCLL = DM37XX_I2C_SCLL,
.I2C_SCLH = DM37XX_I2C_SCLH,
.I2C_SYSTEST = DM37XX_I2C_SYSTEST,
.I2C_BUFSTAT = DM37XX_I2C_BUFSTAT,
.I2C_OA1 = DM37XX_I2C_OA1,
.I2C_OA2 = DM37XX_I2C_OA2,
.I2C_OA3 = DM37XX_I2C_OA3,
.I2C_ACTOA = DM37XX_I2C_ACTOA,
.I2C_SBLOCK = DM37XX_I2C_SBLOCK
};
/* Define the buses available on each chip */
static omap_i2c_bus_t am335x_i2c_buses[] = {
{AM335X_I2C_BUS, AM335X_I2C0_BASE, AM335X_I2C0_SIZE, 0, &am335x_i2c_regs,
AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
BUS_SPEED_400KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
AM335X_I2C0_IRQ, 1, 1},
{AM335X_I2C_BUS, AM335X_I2C1_BASE, AM335X_I2C1_SIZE, 0, &am335x_i2c_regs,
AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
BUS_SPEED_100KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
AM335X_I2C1_IRQ, 2, 3},
{AM335X_I2C_BUS, AM335X_I2C2_BASE, AM335X_I2C2_SIZE, 0, &am335x_i2c_regs,
AM335X_FUNCTIONAL_CLOCK, AM335X_MODULE_CLOCK,
BUS_SPEED_100KHz, AM335X_REV_MAJOR, AM335X_REV_MINOR,
AM335X_I2C2_IRQ, 3, 3}
};
#define AM335X_OMAP_NBUSES (sizeof(am335x_i2c_buses) / sizeof(omap_i2c_bus_t))
static omap_i2c_bus_t dm37xx_i2c_buses[] = {
{DM37XX_I2C_BUS, DM37XX_I2C0_BASE, DM37XX_I2C0_SIZE, 0, &dm37xx_i2c_regs,
DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
DM37XX_I2C0_IRQ, 1, 1},
{DM37XX_I2C_BUS, DM37XX_I2C1_BASE, DM37XX_I2C1_SIZE, 0, &dm37xx_i2c_regs,
DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
DM37XX_I2C1_IRQ, 2, 2},
{DM37XX_I2C_BUS, DM37XX_I2C2_BASE, DM37XX_I2C2_SIZE, 0, &dm37xx_i2c_regs,
DM37XX_FUNCTIONAL_CLOCK, DM37XX_MODULE_CLOCK,
BUS_SPEED_100KHz, DM37XX_REV_MAJOR, DM37XX_REV_MINOR,
DM37XX_I2C2_IRQ, 3, 3}
};
#define DM37XX_OMAP_NBUSES (sizeof(dm37xx_i2c_buses) / sizeof(omap_i2c_bus_t))
/* Globals */
static omap_i2c_bus_t *omap_i2c_buses; /* all available buses for this SoC */
static omap_i2c_bus_t *omap_i2c_bus; /* the bus selected at start-up */
static int omap_i2c_nbuses; /* number of buses supported by SoC */
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
static struct log log = {
.name = "i2c",
.log_level = LEVEL_INFO,
.log_func = default_log
};
/* Local Function Prototypes */
/* Implementation of Generic I2C Interface using Bus Specific Code */
static int omap_i2c_process(minix_i2c_ioctl_exec_t * m);
/* Bus Specific Code */
static void omap_i2c_flush(void);
static uint16_t omap_i2c_poll(uint16_t mask);
static int omap_i2c_bus_is_free(void);
static int omap_i2c_soft_reset(void);
static void omap_i2c_bus_init(void);
static void omap_i2c_padconf(int i2c_bus_id);
static void omap_i2c_clkconf(int i2c_bus_id);
static void omap_i2c_intr_enable(void);
static uint16_t omap_i2c_read_status(void);
static void omap_i2c_write_status(uint16_t mask);
static int omap_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen,
int dostop);
static int omap_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen,
int dostop);
/*
* Performs the action in minix_i2c_ioctl_exec_t.
*/
static int
omap_i2c_process(minix_i2c_ioctl_exec_t * ioctl_exec)
{
int r;
/*
* Zero data bytes transfers are not allowed. The controller treats
* I2C_CNT register value of 0x0 as 65536. This is true for both the
* am335x and dm37xx. Full details in the TRM on the I2C_CNT page.
*/
if (ioctl_exec->iie_buflen == 0) {
return EINVAL;
}
omap_i2c_flush(); /* clear any garbage in the fifo */
/* Check bus busy flag before using the bus */
r = omap_i2c_bus_is_free();
if (r == 0) {
log_warn(&log, "Bus is busy\n");
return EBUSY;
}
if (ioctl_exec->iie_cmdlen > 0) {
r = omap_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_cmd,
ioctl_exec->iie_cmdlen,
!(I2C_OP_READ_P(ioctl_exec->iie_op)));
if (r != OK) {
omap_i2c_soft_reset();
omap_i2c_bus_init();
return r;
}
}
if (I2C_OP_READ_P(ioctl_exec->iie_op)) {
r = omap_i2c_read(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
} else {
r = omap_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
}
if (r != OK) {
omap_i2c_soft_reset();
omap_i2c_bus_init();
return r;
}
return OK;
}
/*
* Drain the incoming FIFO.
*
* Usually called to clear any garbage that may be in the buffer before
* doing a read.
*/
static void
omap_i2c_flush(void)
{
int tries;
int status;
for (tries = 0; tries < 1000; tries++) {
status = omap_i2c_poll(1 << RRDY);
if ((status & (1 << RRDY)) != 0) { /* bytes available for reading */
/* consume the byte and throw it away */
(void) read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA);
/* clear the read ready flag */
omap_i2c_write_status(1 << RRDY);
} else {
break; /* buffer drained */
}
}
}
/*
* Poll the status register checking the bits set in 'mask'.
* Returns the status if any bits set or 0x0000 when the timeout is reached.
*/
static uint16_t
omap_i2c_poll(uint16_t mask)
{
spin_t spin;
uint16_t status;
/* poll for up to 1 s */
spin_init(&spin, 1000000);
do {
status = omap_i2c_read_status();
if ((status & mask) != 0) { /* any bits in mask set */
return status;
}
} while (spin_check(&spin));
return status; /* timeout reached, abort */
}
/*
* Poll Bus Busy Flag until the bus becomes free (return 1) or the timeout
* expires (return 0).
*/
static int
omap_i2c_bus_is_free(void)
{
spin_t spin;
uint16_t status;
/* wait for up to 1 second for the bus to become free */
spin_init(&spin, 1000000);
do {
status = omap_i2c_read_status();
if ((status & (1 << BB)) == 0) {
return 1; /* bus is free */
}
} while (spin_check(&spin));
return 0; /* timeout expired */
}
static void
omap_i2c_clkconf(int i2c_bus_id)
{
clkconf_init();
if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
clkconf_set(CM_ICLKEN1_CORE, BIT((15 + i2c_bus_id)),
0xffffffff);
clkconf_set(CM_FCLKEN1_CORE, BIT((15 + i2c_bus_id)),
0xffffffff);
} else if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
switch (i2c_bus_id) {
case 0:
clkconf_set(CM_WKUP_I2C0_CLKCTRL, BIT(1), 0xffffffff);
break;
case 1:
clkconf_set(CM_PER_I2C1_CLKCTRL, BIT(1), 0xffffffff);
break;
case 2:
clkconf_set(CM_PER_I2C2_CLKCTRL, BIT(1), 0xffffffff);
break;
default:
log_warn(&log, "Invalid i2c_bus_id\n");
break;
}
}
clkconf_release();
}
static void
omap_i2c_padconf(int i2c_bus_id)
{
int r;
u32_t pinopts;
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
/* use the options suggested in starterware driver */
pinopts =
CONTROL_CONF_SLEWCTRL | CONTROL_CONF_RXACTIVE |
CONTROL_CONF_PUTYPESEL;
switch (i2c_bus_id) {
case 0:
pinopts |= CONTROL_CONF_MUXMODE(0);
r = sys_padconf(CONTROL_CONF_I2C0_SDA, 0xffffffff,
pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
r = sys_padconf(CONTROL_CONF_I2C0_SCL, 0xffffffff,
pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
log_debug(&log, "pinopts=0x%x\n", pinopts);
break;
case 1:
pinopts |= CONTROL_CONF_MUXMODE(2);
r = sys_padconf(CONTROL_CONF_SPI0_CS0, 0xffffffff,
pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
r = sys_padconf(CONTROL_CONF_SPI0_D1, 0xffffffff,
pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
log_debug(&log, "pinopts=0x%x\n", pinopts);
break;
case 2:
pinopts |= CONTROL_CONF_MUXMODE(3);
r = sys_padconf(CONTROL_CONF_UART1_CTSN, 0xffffffff,
pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
r = sys_padconf(CONTROL_CONF_UART1_RTSN,
0xffffffff, pinopts);
if (r != OK) {
log_warn(&log, "padconf failed (r=%d)\n", r);
}
log_debug(&log, "pinopts=0x%x\n", pinopts);
break;
default:
log_warn(&log, "Invalid i2c_bus_id\n");
break;
}
}
/* nothing to do for the DM37XX */
}
static int
omap_i2c_soft_reset(void)
{
spin_t spin;
/* Disable to do soft reset */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, 0);
micro_delay(50000);
/* Do a soft reset */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSC, (1 << SRST));
/* Have to temporarily enable I2C to read RDONE */
set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, (1<<I2C_EN), (1<<I2C_EN));
micro_delay(50000);
/* wait up to 3 seconds for reset to complete */
spin_init(&spin, 3000000);
do {
if (read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSS) & (1 << RDONE)) {
return OK;
}
} while (spin_check(&spin));
log_warn(&log, "Tried soft reset, but bus never came back.\n");
return EIO;
}
static void
omap_i2c_intr_enable(void)
{
int r;
uint16_t intmask;
static int policy_set = 0;
static int enabled = 0;
if (!policy_set) {
r = sys_irqsetpolicy(omap_i2c_bus->irq, 0,
&omap_i2c_bus->irq_hook_kernel_id);
if (r == OK) {
policy_set = 1;
} else {
log_warn(&log, "Couldn't set irq policy\n");
}
}
if (policy_set && !enabled) {
r = sys_irqenable(&omap_i2c_bus->irq_hook_kernel_id);
if (r == OK) {
enabled = 1;
} else {
log_warn(&log, "Couldn't enable irq %d (hooked)\n",
omap_i2c_bus->irq);
}
}
/* According to NetBSD driver and u-boot, these are needed even
* if just using polling (i.e. non-interrupt driver programming).
*/
intmask = 0;
intmask |= (1 << ROVR);
intmask |= (1 << AERR);
intmask |= (1 << XRDY);
intmask |= (1 << RRDY);
intmask |= (1 << ARDY);
intmask |= (1 << NACK);
intmask |= (1 << AL);
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQENABLE_SET, intmask);
} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IE, intmask);
} else {
log_warn(&log, "Don't know how to enable interrupts.\n");
}
}
static void
omap_i2c_bus_init(void)
{
/* Ensure i2c module is disabled before setting prescalar & bus speed */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, 0);
micro_delay(50000);
/* Disable autoidle */
set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SYSC, (1<<AUTOIDLE), (0<<AUTOIDLE));
/* Set prescalar to obtain 12 MHz i2c module clock */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_PSC,
((omap_i2c_bus->functional_clock / omap_i2c_bus->module_clock) -
1));
/* Set the bus speed */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SCLL,
((omap_i2c_bus->module_clock / (2 * omap_i2c_bus->bus_speed)) -
7));
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SCLH,
((omap_i2c_bus->module_clock / (2 * omap_i2c_bus->bus_speed)) -
5));
/* Set own I2C address */
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_OA, I2C_OWN_ADDRESS);
} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_OA0, I2C_OWN_ADDRESS);
} else {
log_warn(&log, "Don't know how to set own address.\n");
}
/* Set TX/RX Threshold to 1 and disable I2C DMA */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_BUF, 0x0000);
/* Bring the i2c module out of reset */
set16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, (1<<I2C_EN), (1<<I2C_EN));
micro_delay(50000);
/*
* Enable interrupts
*/
omap_i2c_intr_enable();
}
static uint16_t
omap_i2c_read_status(void)
{
uint16_t status = 0x0000;
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
/* TRM says to use RAW for polling for events */
status = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQSTATUS_RAW);
} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
status = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_STAT);
} else {
log_warn(&log, "Don't know how to read i2c bus status.\n");
}
return status;
}
static void
omap_i2c_write_status(uint16_t mask)
{
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
/* write 1's to IRQSTATUS (not RAW) to clear the bits */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_IRQSTATUS, mask);
} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_STAT, mask);
} else {
log_warn(&log, "Don't know how to clear i2c bus status.\n");
}
}
static int
omap_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen, int dostop)
{
int r, i;
uint16_t conopts;
uint16_t pollmask;
uint16_t errmask;
/* Set address of slave device */
conopts = 0;
addr &= MAX_I2C_SA_MASK; /* sanitize address (10-bit max) */
if (addr > 0x7f) {
/* 10-bit extended address in use, need to set XSA */
conopts |= (1 << XSA);
}
errmask = 0;
errmask |= (1 << ROVR);
errmask |= (1 << AERR);
errmask |= (1 << NACK);
errmask |= (1 << AL);
pollmask = 0;
pollmask |= (1 << RRDY);
/* Set bytes to read and slave address */
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CNT, buflen);
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SA, addr);
/* Set control register */
conopts |= (1 << I2C_EN); /* enabled */
conopts |= (1 << MST); /* master mode */
conopts |= (1 << STT); /* start condition */
if (dostop != 0) {
conopts |= (1 << STP); /* stop condition */
}
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, conopts);
for (i = 0; i < buflen; i++) {
/* Data to read? */
r = omap_i2c_poll(pollmask | errmask);
if ((r & errmask) != 0) {
/* only debug log level because i2cscan trigers this */
log_debug(&log, "Read Error! Status=%x\n", r);
return EIO;
} else if ((r & pollmask) == 0) {
log_warn(&log, "No RRDY Interrupt. Status=%x\n", r);
log_warn(&log,
"Likely cause: bad pinmux or no devices on bus\n");
return EBUSY;
}
/* read a byte */
buf[i] = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA) & 0xff;
/* clear the read ready flag */
omap_i2c_write_status(pollmask);
}
r = omap_i2c_read_status();
if ((r & (1 << NACK)) != 0) {
log_warn(&log, "NACK\n");
return EIO;
}
/* Wait for operation to complete */
pollmask = (1<<ARDY); /* poll access ready bit */
r = omap_i2c_poll(pollmask);
if ((r & pollmask) == 0) {
log_warn(&log, "Read operation never finished.\n");
return EBUSY;
}
omap_i2c_write_status(0x7fff);
return 0;
}
static int
omap_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen, int dostop)
{
int r, i;
uint16_t conopts;
uint16_t pollmask;
uint16_t errmask;
/* Set address of slave device */
conopts = 0;
addr &= MAX_I2C_SA_MASK; /* sanitize address (10-bit max) */
if (addr > 0x7f) {
/* 10-bit extended address in use, need to set XSA */
conopts |= (1 << XSA);
}
pollmask = 0;
pollmask |= (1 << XRDY);
errmask = 0;
errmask |= (1 << ROVR);
errmask |= (1 << AERR);
errmask |= (1 << NACK);
errmask |= (1 << AL);
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CNT, buflen);
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_SA, addr);
/* Set control register */
conopts |= (1 << I2C_EN); /* enabled */
conopts |= (1 << MST); /* master mode */
conopts |= (1 << TRX); /* TRX mode */
conopts |= (1 << STT); /* start condition */
if (dostop != 0) {
conopts |= (1 << STP); /* stop condition */
}
omap_i2c_write_status(0x7fff);
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_CON, conopts);
for (i = 0; i < buflen; i++) {
/* Ready to write? */
r = omap_i2c_poll(pollmask | errmask);
if ((r & errmask) != 0) {
log_warn(&log, "Write Error! Status=%x\n", r);
return EIO;
} else if ((r & pollmask) == 0) {
log_warn(&log, "Not ready for write? Status=%x\n", r);
return EBUSY;
}
write16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_DATA, buf[i]);
/* clear the write ready flag */
omap_i2c_write_status(pollmask);
}
r = omap_i2c_read_status();
if ((r & (1 << NACK)) != 0) {
log_warn(&log, "NACK\n");
return EIO;
}
/* Wait for operation to complete */
pollmask = (1<<ARDY); /* poll access ready bit */
r = omap_i2c_poll(pollmask);
if ((r & pollmask) == 0) {
log_warn(&log, "Write operation never finished.\n");
return EBUSY;
}
omap_i2c_write_status(0x7fff);
return 0;
}
int
omap_interface_setup(int (**process) (minix_i2c_ioctl_exec_t * ioctl_exec),
int i2c_bus_id)
{
int r;
int i2c_rev, major, minor;
struct minix_mem_range mr;
struct machine machine;
sys_getmachine(&machine);
/* Fill in the function pointer */
*process = omap_i2c_process;
/* Select the correct i2c definition for this SoC */
if (BOARD_IS_BBXM(machine.board_id)){
omap_i2c_buses = dm37xx_i2c_buses;
omap_i2c_nbuses = DM37XX_OMAP_NBUSES;
} else if (BOARD_IS_BB(machine.board_id)){
omap_i2c_buses = am335x_i2c_buses;
omap_i2c_nbuses = AM335X_OMAP_NBUSES;
} else {
return EINVAL;
}
if (i2c_bus_id < 0 || i2c_bus_id >= omap_i2c_nbuses) {
return EINVAL;
}
/* select the bus to operate on */
omap_i2c_bus = &omap_i2c_buses[i2c_bus_id];
/* Configure Pins */
omap_i2c_padconf(i2c_bus_id);
/*
* Map I2C Registers
*/
/* Configure memory access */
mr.mr_base = omap_i2c_bus->mr_base; /* start addr */
mr.mr_limit = mr.mr_base + omap_i2c_bus->mr_size; /* end addr */
/* ask for privileges to access the I2C memory range */
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to obtain i2c memory range privileges");
}
/* map the memory into this process */
omap_i2c_bus->mapped_addr = (vir_bytes) vm_map_phys(SELF,
(void *) omap_i2c_bus->mr_base, omap_i2c_bus->mr_size);
if (omap_i2c_bus->mapped_addr == (vir_bytes) MAP_FAILED) {
panic("Unable to map i2c registers");
}
/* Enable Clocks */
omap_i2c_clkconf(i2c_bus_id);
/* Perform a soft reset of the I2C module to ensure a fresh start */
r = omap_i2c_soft_reset();
if (r != OK) {
/* module didn't come back up :( */
return r;
}
/* Bring up I2C module */
omap_i2c_bus_init();
/* Get I2C Revision */
if (omap_i2c_bus->bus_type == AM335X_I2C_BUS) {
/* I2C_REVLO revision: major (bits 10-8), minor (bits 5-0) */
i2c_rev = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_REVNB_LO);
major = (i2c_rev >> 8) & 0x07;
minor = i2c_rev & 0x3f;
} else if (omap_i2c_bus->bus_type == DM37XX_I2C_BUS) {
/* I2C_REV revision: major (bits 7-4), minor (bits 3-0) */
i2c_rev = read16(omap_i2c_bus->mapped_addr + omap_i2c_bus->regs->I2C_REV);
major = (i2c_rev >> 4) & 0x0f;
minor = i2c_rev & 0x0f;
} else {
panic("Don't know how to read i2c revision.");
}
if (major != omap_i2c_bus->major || minor != omap_i2c_bus->minor) {
log_warn(&log, "Unrecognized value in I2C_REV register.\n");
log_warn(&log, "Read: 0x%x.0x%x | Expected: 0x%x.0x%x\n",
major, minor, omap_i2c_bus->major, omap_i2c_bus->minor);
}
/* display i2c revision information for debugging purposes */
log_debug(&log, "i2c_%d: I2C rev 0x%x.0x%x\n", (i2c_bus_id + 1),
major, minor);
return OK;
}

View File

@@ -0,0 +1,10 @@
#ifndef _OMAP_I2C_H
#define _OMAP_I2C_H
#include <minix/chardriver.h>
#include <minix/i2c.h>
#include "omap_i2c_registers.h"
int omap_interface_setup(int (**process)(minix_i2c_ioctl_exec_t *ioctl_exec), int i2c_bus_id);
#endif /* _OMAP_I2C_H */

View File

@@ -0,0 +1,152 @@
#ifndef _OMAP_I2C_REGISTERS_H
#define _OMAP_I2C_REGISTERS_H
/* I2C Addresses for am335x (BeagleBone White / BeagleBone Black) */
/* IRQ Numbers */
#define AM335X_I2C0_IRQ 70
#define AM335X_I2C1_IRQ 71
#define AM335X_I2C2_IRQ 30
/* Base Addresses */
#define AM335X_I2C0_BASE 0x44e0b000
#define AM335X_I2C1_BASE 0x4802a000
#define AM335X_I2C2_BASE 0x4819c000
/* Size of I2C Register Address Range */
#define AM335X_I2C0_SIZE 0x1000
#define AM335X_I2C1_SIZE 0x1000
#define AM335X_I2C2_SIZE 0x1000
/* Register Offsets */
#define AM335X_I2C_REVNB_LO 0x00
#define AM335X_I2C_REVNB_HI 0x04
#define AM335X_I2C_SYSC 0x10
#define AM335X_I2C_IRQSTATUS_RAW 0x24
#define AM335X_I2C_IRQSTATUS 0x28
#define AM335X_I2C_IRQENABLE_SET 0x2c
#define AM335X_I2C_IRQENABLE_CLR 0x30
#define AM335X_I2C_WE 0x34
#define AM335X_I2C_DMARXENABLE_SET 0x38
#define AM335X_I2C_DMATXENABLE_SET 0x3c
#define AM335X_I2C_DMARXENABLE_CLR 0x40
#define AM335X_I2C_DMATXENABLE_CLR 0x44
#define AM335X_I2C_DMARXWAKE_EN 0x48
#define AM335X_I2C_DMATXWAKE_EN 0x4c
#define AM335X_I2C_SYSS 0x90
#define AM335X_I2C_BUF 0x94
#define AM335X_I2C_CNT 0x98
#define AM335X_I2C_DATA 0x9c
#define AM335X_I2C_CON 0xa4
#define AM335X_I2C_OA 0xa8
#define AM335X_I2C_SA 0xac
#define AM335X_I2C_PSC 0xb0
#define AM335X_I2C_SCLL 0xb4
#define AM335X_I2C_SCLH 0xb8
#define AM335X_I2C_SYSTEST 0xbc
#define AM335X_I2C_BUFSTAT 0xc0
#define AM335X_I2C_OA1 0xc4
#define AM335X_I2C_OA2 0xc8
#define AM335X_I2C_OA3 0xcc
#define AM335X_I2C_ACTOA 0xd0
#define AM335X_I2C_SBLOCK 0xd4
/* Constants */
#define AM335X_FUNCTIONAL_CLOCK 96000000 /* 96 MHz */
#define AM335X_MODULE_CLOCK 12000000 /* 12 MHz */
/* I2C_REV value found on the BeagleBone / BeagleBone Black */
#define AM335X_REV_MAJOR 0x00
#define AM335X_REV_MINOR 0x0b
/* I2C Addresses for dm37xx (BeagleBoard-xM) */
/* IRQ Numbers */
#define DM37XX_I2C0_IRQ 56
#define DM37XX_I2C1_IRQ 57
#define DM37XX_I2C2_IRQ 61
/* Base Addresses */
#define DM37XX_I2C0_BASE 0x48070000
#define DM37XX_I2C1_BASE 0x48072000
#define DM37XX_I2C2_BASE 0x48060000
/* Size of I2C Register Address Range */
#define DM37XX_I2C0_SIZE 0x1000
#define DM37XX_I2C1_SIZE 0x1000
#define DM37XX_I2C2_SIZE 0x1000
/* Register Offsets */
#define DM37XX_I2C_REV 0x00
#define DM37XX_I2C_IE 0x04
#define DM37XX_I2C_STAT 0x08
#define DM37XX_I2C_WE 0x0C
#define DM37XX_I2C_SYSS 0x10
#define DM37XX_I2C_BUF 0x14
#define DM37XX_I2C_CNT 0x18
#define DM37XX_I2C_DATA 0x1c
#define DM37XX_I2C_SYSC 0x20
#define DM37XX_I2C_CON 0x24
#define DM37XX_I2C_OA0 0x28
#define DM37XX_I2C_SA 0x2c
#define DM37XX_I2C_PSC 0x30
#define DM37XX_I2C_SCLL 0x34
#define DM37XX_I2C_SCLH 0x38
#define DM37XX_I2C_SYSTEST 0x3c
#define DM37XX_I2C_BUFSTAT 0x40
#define DM37XX_I2C_OA1 0x44
#define DM37XX_I2C_OA2 0x48
#define DM37XX_I2C_OA3 0x4c
#define DM37XX_I2C_ACTOA 0x50
#define DM37XX_I2C_SBLOCK 0x54
/* Constants */
#define DM37XX_FUNCTIONAL_CLOCK 96000000 /* 96 MHz */
#define DM37XX_MODULE_CLOCK 19200000 /* 19.2 MHz */
#define DM37XX_REV_MAJOR 0x04
#define DM37XX_REV_MINOR 0x00
/* Shared Values */
#define BUS_SPEED_100KHz 100000 /* 100 KHz */
#define BUS_SPEED_400KHz 400000 /* 400 KHz */
#define I2C_OWN_ADDRESS 0x01
/* Masks */
#define MAX_I2C_SA_MASK (0x3ff) /* Highest 10 bit address -- 9..0 */
/* Bit Offsets within Registers (only those used are listed) */
/* Same offsets for both dm37xx and am335x */
#define I2C_EN 15 /* I2C_CON */
#define MST 10 /* I2C_CON */
#define TRX 9 /* I2C_CON */
#define XSA 8 /* I2C_CON */
#define STP 1 /* I2C_CON */
#define STT 0 /* I2C_CON */
#define CLKACTIVITY_S 9 /* I2C_SYSC */
#define CLKACTIVITY_I 8 /* I2C_SYSC */
#define SMART_WAKE_UP 4 /* I2C_SYSC */
#define NO_IDLE_MODE 3 /* I2C_SYSC */
#define SRST 1 /* I2C_SYSC */
#define AUTOIDLE 0 /* I2C_SYSC */
#define RDONE 0 /* I2C_SYSS */
#define RXFIFO_CLR 14 /* I2C_BUF */
#define TXFIFO_CLR 6 /* I2C_BUF */
#define BB 12 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define ROVR 11 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define AERR 7 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define XRDY 4 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define RRDY 3 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define ARDY 2 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define NACK 1 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#define AL 0 /* I2C_IRQSTATUS / I2C_STAT / I2C_IRQENABLE_SET / I2C_IE */
#endif /* _OMAP_I2C_REGISTERS_H */

View File

@@ -0,0 +1,10 @@
# Makefile for arch-dependent readclock code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS += arch_readclock.c omap_rtc.c omap_rtc.h
DPADD+= ${LIBCLKCONF}
LDADD+= -lclkconf

View File

@@ -0,0 +1,45 @@
#include <minix/syslib.h>
#include <minix/drvlib.h>
#include <minix/sysutil.h>
#include <minix/type.h>
#include <minix/board.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include "omap_rtc.h"
#include "forward.h"
#include "readclock.h"
int
arch_setup(struct rtc *r)
{
struct machine machine ;
sys_getmachine(&machine);
if (BOARD_IS_BBXM(machine.board_id)){
fwd_set_label("tps65950.1.48");
r->init = fwd_init;
r->get_time = fwd_get_time;
r->set_time = fwd_set_time;
r->pwr_off = fwd_pwr_off;
r->exit = fwd_exit;
return OK;
} else if ( BOARD_IS_BB(machine.board_id)){
r->init = omap_rtc_init;
r->get_time = omap_rtc_get_time;
r->set_time = omap_rtc_set_time;
r->pwr_off = omap_rtc_pwr_off;
r->exit = omap_rtc_exit;
return OK;
}
return ENOSYS;
}

View File

@@ -0,0 +1,419 @@
#include <minix/syslib.h>
#include <minix/drvlib.h>
#include <minix/log.h>
#include <minix/mmio.h>
#include <minix/clkconf.h>
#include <minix/sysutil.h>
#include <minix/board.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include "omap_rtc.h"
#include "readclock.h"
/* defines the set of register */
typedef struct omap_rtc_registers
{
vir_bytes RTC_SS_SECONDS_REG;
vir_bytes RTC_SS_MINUTES_REG;
vir_bytes RTC_SS_HOURS_REG;
vir_bytes RTC_SS_DAYS_REG;
vir_bytes RTC_SS_MONTHS_REG;
vir_bytes RTC_SS_YEARS_REG;
vir_bytes RTC_SS_WEEKS_REG;
vir_bytes RTC_SS_ALARM_SECONDS_REG;
vir_bytes RTC_SS_ALARM_MINUTES_REG;
vir_bytes RTC_SS_ALARM_HOURS_REG;
vir_bytes RTC_SS_ALARM_DAYS_REG;
vir_bytes RTC_SS_ALARM_MONTHS_REG;
vir_bytes RTC_SS_ALARM_YEARS_REG;
vir_bytes RTC_SS_RTC_CTRL_REG;
vir_bytes RTC_SS_RTC_STATUS_REG;
vir_bytes RTC_SS_RTC_INTERRUPTS_REG;
vir_bytes RTC_SS_RTC_COMP_LSB_REG;
vir_bytes RTC_SS_RTC_COMP_MSB_REG;
vir_bytes RTC_SS_RTC_OSC_REG;
vir_bytes RTC_SS_RTC_SCRATCH0_REG;
vir_bytes RTC_SS_RTC_SCRATCH1_REG;
vir_bytes RTC_SS_RTC_SCRATCH2_REG;
vir_bytes RTC_SS_KICK0R;
vir_bytes RTC_SS_KICK1R;
vir_bytes RTC_SS_RTC_REVISION;
vir_bytes RTC_SS_RTC_SYSCONFIG;
vir_bytes RTC_SS_RTC_IRQWAKEEN;
vir_bytes RTC_SS_ALARM2_SECONDS_REG;
vir_bytes RTC_SS_ALARM2_MINUTES_REG;
vir_bytes RTC_SS_ALARM2_HOURS_REG;
vir_bytes RTC_SS_ALARM2_DAYS_REG;
vir_bytes RTC_SS_ALARM2_MONTHS_REG;
vir_bytes RTC_SS_ALARM2_YEARS_REG;
vir_bytes RTC_SS_RTC_PMIC;
vir_bytes RTC_SS_RTC_DEBOUNCE;
} omap_rtc_registers_t;
typedef struct omap_rtc_clock
{
enum rtc_clock_type
{ am335x } clock_type;
phys_bytes mr_base;
phys_bytes mr_size;
vir_bytes mapped_addr;
omap_rtc_registers_t *regs;
} omap_rtc_clock_t;
/* Define the registers for each chip */
static omap_rtc_registers_t am335x_rtc_regs = {
.RTC_SS_SECONDS_REG = AM335X_RTC_SS_SECONDS_REG,
.RTC_SS_MINUTES_REG = AM335X_RTC_SS_MINUTES_REG,
.RTC_SS_HOURS_REG = AM335X_RTC_SS_HOURS_REG,
.RTC_SS_DAYS_REG = AM335X_RTC_SS_DAYS_REG,
.RTC_SS_MONTHS_REG = AM335X_RTC_SS_MONTHS_REG,
.RTC_SS_YEARS_REG = AM335X_RTC_SS_YEARS_REG,
.RTC_SS_WEEKS_REG = AM335X_RTC_SS_WEEKS_REG,
.RTC_SS_ALARM_SECONDS_REG = AM335X_RTC_SS_ALARM_SECONDS_REG,
.RTC_SS_ALARM_MINUTES_REG = AM335X_RTC_SS_ALARM_MINUTES_REG,
.RTC_SS_ALARM_HOURS_REG = AM335X_RTC_SS_ALARM_HOURS_REG,
.RTC_SS_ALARM_DAYS_REG = AM335X_RTC_SS_ALARM_DAYS_REG,
.RTC_SS_ALARM_MONTHS_REG = AM335X_RTC_SS_ALARM_MONTHS_REG,
.RTC_SS_ALARM_YEARS_REG = AM335X_RTC_SS_ALARM_YEARS_REG,
.RTC_SS_RTC_CTRL_REG = AM335X_RTC_SS_RTC_CTRL_REG,
.RTC_SS_RTC_STATUS_REG = AM335X_RTC_SS_RTC_STATUS_REG,
.RTC_SS_RTC_INTERRUPTS_REG = AM335X_RTC_SS_RTC_INTERRUPTS_REG,
.RTC_SS_RTC_COMP_LSB_REG = AM335X_RTC_SS_RTC_COMP_LSB_REG,
.RTC_SS_RTC_COMP_MSB_REG = AM335X_RTC_SS_RTC_COMP_MSB_REG,
.RTC_SS_RTC_OSC_REG = AM335X_RTC_SS_RTC_OSC_REG,
.RTC_SS_RTC_SCRATCH0_REG = AM335X_RTC_SS_RTC_SCRATCH0_REG,
.RTC_SS_RTC_SCRATCH1_REG = AM335X_RTC_SS_RTC_SCRATCH1_REG,
.RTC_SS_RTC_SCRATCH2_REG = AM335X_RTC_SS_RTC_SCRATCH2_REG,
.RTC_SS_KICK0R = AM335X_RTC_SS_KICK0R,
.RTC_SS_KICK1R = AM335X_RTC_SS_KICK1R,
.RTC_SS_RTC_REVISION = AM335X_RTC_SS_RTC_REVISION,
.RTC_SS_RTC_SYSCONFIG = AM335X_RTC_SS_RTC_SYSCONFIG,
.RTC_SS_RTC_IRQWAKEEN = AM335X_RTC_SS_RTC_IRQWAKEEN,
.RTC_SS_ALARM2_SECONDS_REG = AM335X_RTC_SS_ALARM2_SECONDS_REG,
.RTC_SS_ALARM2_MINUTES_REG = AM335X_RTC_SS_ALARM2_MINUTES_REG,
.RTC_SS_ALARM2_HOURS_REG = AM335X_RTC_SS_ALARM2_HOURS_REG,
.RTC_SS_ALARM2_DAYS_REG = AM335X_RTC_SS_ALARM2_DAYS_REG,
.RTC_SS_ALARM2_MONTHS_REG = AM335X_RTC_SS_ALARM2_MONTHS_REG,
.RTC_SS_ALARM2_YEARS_REG = AM335X_RTC_SS_ALARM2_YEARS_REG,
.RTC_SS_RTC_PMIC = AM335X_RTC_SS_RTC_PMIC,
.RTC_SS_RTC_DEBOUNCE = AM335X_RTC_SS_RTC_DEBOUNCE
};
static omap_rtc_clock_t rtc = {
am335x, AM335X_RTC_SS_BASE, AM335X_RTC_SS_SIZE, 0, &am335x_rtc_regs
};
/* used for logging */
static struct log log = {
.name = "omap_rtc",
.log_level = LEVEL_INFO,
.log_func = default_log
};
static u32_t use_count = 0;
static u32_t pwr_off_in_progress = 0;
static void omap_rtc_unlock(void);
static void omap_rtc_lock(void);
static int omap_rtc_clkconf(void);
/* Helper Functions for Register Access */
#define reg_read(a) (*(volatile uint32_t *)(rtc.mapped_addr + a))
#define reg_write(a,v) (*(volatile uint32_t *)(rtc.mapped_addr + a) = (v))
#define reg_set_bit(a,v) reg_write((a), reg_read((a)) | (1<<v))
#define reg_clear_bit(a,v) reg_write((a), reg_read((a)) & ~(1<<v))
#define RTC_IS_BUSY (reg_read(rtc.regs->RTC_SS_RTC_STATUS_REG) & (1<<RTC_BUSY_BIT))
/* When the RTC is running, writes should not happen when the RTC is busy.
* This macro waits until the RTC is free before doing the write.
*/
#define safe_reg_write(a,v) do { while (RTC_IS_BUSY) {micro_delay(1);} reg_write((a),(v)); } while (0)
#define safe_reg_set_bit(a,v) safe_reg_write((a), reg_read((a)) | (1<<v))
#define safe_reg_clear_bit(a,v) safe_reg_write((a), reg_read((a)) & ~(1<<v))
static void
omap_rtc_unlock(void)
{
/* Specific bit patterns need to be written to specific registers in a
* specific order to enable writing to RTC_SS registers.
*/
reg_write(rtc.regs->RTC_SS_KICK0R, AM335X_RTC_SS_KICK0R_UNLOCK_MASK);
reg_write(rtc.regs->RTC_SS_KICK1R, AM335X_RTC_SS_KICK1R_UNLOCK_MASK);
}
static void
omap_rtc_lock(void)
{
/* Write garbage to the KICK registers to enable write protect. */
reg_write(rtc.regs->RTC_SS_KICK0R, AM335X_RTC_SS_KICK0R_LOCK_MASK);
reg_write(rtc.regs->RTC_SS_KICK1R, AM335X_RTC_SS_KICK1R_LOCK_MASK);
}
static int
omap_rtc_clkconf(void)
{
int r;
/* Configure the clocks need to run the RTC */
r = clkconf_init();
if (r != OK) {
return r;
}
r = clkconf_set(CM_RTC_RTC_CLKCTRL, 0xffffffff,
CM_RTC_RTC_CLKCTRL_MASK);
if (r != OK) {
return r;
}
r = clkconf_set(CM_RTC_CLKSTCTRL, 0xffffffff, CM_RTC_CLKSTCTRL_MASK);
if (r != OK) {
return r;
}
r = clkconf_release();
if (r != OK) {
return r;
}
return OK;
}
int
omap_rtc_init(void)
{
int r;
int rtc_rev, major, minor;
struct minix_mem_range mr;
struct machine machine ;
sys_getmachine(&machine);
if(! BOARD_IS_BB(machine.board_id)){
/* Only the am335x (BeagleBone & BeagleBone Black) is supported ATM.
* The dm37xx (BeagleBoard-xM) doesn't have a real time clock
* built-in. Instead, it uses the RTC on the PMIC. A driver for
* the BeagleBoard-xM's PMIC still needs to be developed.
*/
log_warn(&log, "unsupported processor\n");
return ENOSYS;
}
if (pwr_off_in_progress)
return EINVAL;
use_count++;
if (rtc.mapped_addr != 0) {
/* already intialized */
return OK;
}
/* Enable Clocks */
r = omap_rtc_clkconf();
if (r != OK) {
log_warn(&log, "Failed to enable clocks for RTC.\n");
return r;
}
/*
* Map RTC_SS Registers
*/
/* Configure memory access */
mr.mr_base = rtc.mr_base; /* start addr */
mr.mr_limit = mr.mr_base + rtc.mr_size; /* end addr */
/* ask for privileges to access the RTC_SS memory range */
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
log_warn(&log,
"Unable to obtain RTC memory range privileges.");
return EPERM;
}
/* map the memory into this process */
rtc.mapped_addr = (vir_bytes) vm_map_phys(SELF,
(void *) rtc.mr_base, rtc.mr_size);
if (rtc.mapped_addr == (vir_bytes) MAP_FAILED) {
log_warn(&log, "Unable to map RTC registers\n");
return EPERM;
}
rtc_rev = reg_read(rtc.regs->RTC_SS_RTC_REVISION);
major = (rtc_rev & 0x0700) >> 8;
minor = (rtc_rev & 0x001f);
log_debug(&log, "omap rtc rev %d.%d\n", major, minor);
/* Disable register write protect */
omap_rtc_unlock();
/* Set NOIDLE */
reg_write(rtc.regs->RTC_SS_RTC_SYSCONFIG, (1 << NOIDLE_BIT));
/* Enable 32kHz clock */
reg_set_bit(rtc.regs->RTC_SS_RTC_OSC_REG, EN_32KCLK_BIT);
/* Setting the stop bit starts the RTC running */
reg_set_bit(rtc.regs->RTC_SS_RTC_CTRL_REG, RTC_STOP_BIT);
/* Re-enable Write Protection */
omap_rtc_lock();
log_debug(&log, "OMAP RTC Initialized\n");
return OK;
}
/*
* These are the ranges used by the real time clock and struct tm.
*
* Field OMAP RTC struct tm
* ----- -------- ---------
* seconds 0 to 59 (Mask 0x7f) 0 to 59 (60 for leap seconds)
* minutes 0 to 59 (Mask 0x7f) 0 to 59
* hours 0 to 23 (Mask 0x3f) 0 to 23
* day 1 to 31 (Mask 0x3f) 1 to 31
* month 1 to 12 (Mask 0x1f) 0 to 11
* year last 2 digits of year X + 1900
*/
int
omap_rtc_get_time(struct tm *t, int flags)
{
int r;
if (pwr_off_in_progress)
return EINVAL;
memset(t, '\0', sizeof(struct tm));
/* Read and Convert BCD to binary (default RTC mode). */
t->tm_sec = bcd_to_dec(reg_read(rtc.regs->RTC_SS_SECONDS_REG) & 0x7f);
t->tm_min = bcd_to_dec(reg_read(rtc.regs->RTC_SS_MINUTES_REG) & 0x7f);
t->tm_hour = bcd_to_dec(reg_read(rtc.regs->RTC_SS_HOURS_REG) & 0x3f);
t->tm_mday = bcd_to_dec(reg_read(rtc.regs->RTC_SS_DAYS_REG) & 0x3f);
t->tm_mon =
bcd_to_dec(reg_read(rtc.regs->RTC_SS_MONTHS_REG) & 0x1f) - 1;
t->tm_year =
bcd_to_dec(reg_read(rtc.regs->RTC_SS_YEARS_REG) & 0xff) + 100;
if (t->tm_year == 100) {
/* Cold start - no date/time set - default to 2013-01-01 */
t->tm_sec = 0;
t->tm_min = 0;
t->tm_hour = 0;
t->tm_mday = 1;
t->tm_mon = 0;
t->tm_year = 113;
omap_rtc_set_time(t, RTCDEV_NOFLAGS);
}
return OK;
}
int
omap_rtc_set_time(struct tm *t, int flags)
{
int r;
if (pwr_off_in_progress)
return EINVAL;
/* Disable Write Protection */
omap_rtc_unlock();
/* Write the date/time to the RTC registers. */
safe_reg_write(rtc.regs->RTC_SS_SECONDS_REG,
(dec_to_bcd(t->tm_sec) & 0x7f));
safe_reg_write(rtc.regs->RTC_SS_MINUTES_REG,
(dec_to_bcd(t->tm_min) & 0x7f));
safe_reg_write(rtc.regs->RTC_SS_HOURS_REG,
(dec_to_bcd(t->tm_hour) & 0x3f));
safe_reg_write(rtc.regs->RTC_SS_DAYS_REG,
(dec_to_bcd(t->tm_mday) & 0x3f));
safe_reg_write(rtc.regs->RTC_SS_MONTHS_REG,
(dec_to_bcd(t->tm_mon + 1) & 0x1f));
safe_reg_write(rtc.regs->RTC_SS_YEARS_REG,
(dec_to_bcd(t->tm_year % 100) & 0xff));
/* Re-enable Write Protection */
omap_rtc_lock();
return OK;
}
int
omap_rtc_pwr_off(void)
{
int r;
struct tm t;
if (pwr_off_in_progress)
return EINVAL;
/* wait until 3 seconds can be added without overflowing tm_sec */
do {
omap_rtc_get_time(&t, RTCDEV_NOFLAGS);
micro_delay(250000);
} while (t.tm_sec >= 57);
/* set the alarm for 3 seconds from now */
t.tm_sec += 3;
/* Disable register write protect */
omap_rtc_unlock();
/* enable power-off via ALARM2 by setting the PWR_ENABLE_EN bit. */
safe_reg_set_bit(rtc.regs->RTC_SS_RTC_PMIC, PWR_ENABLE_EN_BIT);
/* Write the date/time to the RTC registers. */
safe_reg_write(rtc.regs->RTC_SS_ALARM2_SECONDS_REG,
(dec_to_bcd(t.tm_sec) & 0x7f));
safe_reg_write(rtc.regs->RTC_SS_ALARM2_MINUTES_REG,
(dec_to_bcd(t.tm_min) & 0x7f));
safe_reg_write(rtc.regs->RTC_SS_ALARM2_HOURS_REG,
(dec_to_bcd(t.tm_hour) & 0x3f));
safe_reg_write(rtc.regs->RTC_SS_ALARM2_DAYS_REG,
(dec_to_bcd(t.tm_mday) & 0x3f));
safe_reg_write(rtc.regs->RTC_SS_ALARM2_MONTHS_REG,
(dec_to_bcd(t.tm_mon + 1) & 0x1f));
safe_reg_write(rtc.regs->RTC_SS_ALARM2_YEARS_REG,
(dec_to_bcd(t.tm_year % 100) & 0xff));
/* enable interrupt to trigger POWER_EN to go low when alarm2 hits. */
safe_reg_set_bit(rtc.regs->RTC_SS_RTC_INTERRUPTS_REG, IT_ALARM2_BIT);
/* pause the realtime clock. the kernel will enable it when safe. */
reg_clear_bit(rtc.regs->RTC_SS_RTC_CTRL_REG, RTC_STOP_BIT);
/* Set this flag to block all other operations so that the clock isn't
* accidentally re-startered and so write protect isn't re-enabled. */
pwr_off_in_progress = 1;
/* Make the kernel's job easier by not re-enabling write protection */
return OK;
}
void
omap_rtc_exit(void)
{
use_count--;
if (use_count == 0) {
vm_unmap_phys(SELF, (void *) rtc.mapped_addr, rtc.mr_size);
rtc.mapped_addr = 0;
}
log_debug(&log, "Exiting\n");
}

View File

@@ -0,0 +1,94 @@
#ifndef __OMAP_RTC_REGISTERS_H
#define __OMAP_RTC_REGISTERS_H
/* RTC Addresses for am335x (BeagleBone White / BeagleBone Black) */
/* Base Addresses */
#define AM335X_RTC_SS_BASE 0x44e3e000
/* Size of RTC Register Address Range */
#define AM335X_RTC_SS_SIZE 0x1000
/* Register Offsets */
#define AM335X_RTC_SS_SECONDS_REG 0x0
#define AM335X_RTC_SS_MINUTES_REG 0x4
#define AM335X_RTC_SS_HOURS_REG 0x8
#define AM335X_RTC_SS_DAYS_REG 0xC
#define AM335X_RTC_SS_MONTHS_REG 0x10
#define AM335X_RTC_SS_YEARS_REG 0x14
#define AM335X_RTC_SS_WEEKS_REG 0x18
#define AM335X_RTC_SS_ALARM_SECONDS_REG 0x20
#define AM335X_RTC_SS_ALARM_MINUTES_REG 0x24
#define AM335X_RTC_SS_ALARM_HOURS_REG 0x28
#define AM335X_RTC_SS_ALARM_DAYS_REG 0x2C
#define AM335X_RTC_SS_ALARM_MONTHS_REG 0x30
#define AM335X_RTC_SS_ALARM_YEARS_REG 0x34
#define AM335X_RTC_SS_RTC_CTRL_REG 0x40
#define AM335X_RTC_SS_RTC_STATUS_REG 0x44
#define AM335X_RTC_SS_RTC_INTERRUPTS_REG 0x48
#define AM335X_RTC_SS_RTC_COMP_LSB_REG 0x4C
#define AM335X_RTC_SS_RTC_COMP_MSB_REG 0x50
#define AM335X_RTC_SS_RTC_OSC_REG 0x54
#define AM335X_RTC_SS_RTC_SCRATCH0_REG 0x60
#define AM335X_RTC_SS_RTC_SCRATCH1_REG 0x64
#define AM335X_RTC_SS_RTC_SCRATCH2_REG 0x68
#define AM335X_RTC_SS_KICK0R 0x6C
#define AM335X_RTC_SS_KICK1R 0x70
#define AM335X_RTC_SS_RTC_REVISION 0x74
#define AM335X_RTC_SS_RTC_SYSCONFIG 0x78
#define AM335X_RTC_SS_RTC_IRQWAKEEN 0x7C
#define AM335X_RTC_SS_ALARM2_SECONDS_REG 0x80
#define AM335X_RTC_SS_ALARM2_MINUTES_REG 0x84
#define AM335X_RTC_SS_ALARM2_HOURS_REG 0x88
#define AM335X_RTC_SS_ALARM2_DAYS_REG 0x8C
#define AM335X_RTC_SS_ALARM2_MONTHS_REG 0x90
#define AM335X_RTC_SS_ALARM2_YEARS_REG 0x94
#define AM335X_RTC_SS_RTC_PMIC 0x98
#define AM335X_RTC_SS_RTC_DEBOUNCE 0x9C
/* Constants */
#define AM335X_RTC_SS_KICK0R_UNLOCK_MASK 0x83E70B13
#define AM335X_RTC_SS_KICK1R_UNLOCK_MASK 0x95A4F1E0
#define AM335X_RTC_SS_KICK0R_LOCK_MASK 0x546f6d20
#define AM335X_RTC_SS_KICK1R_LOCK_MASK 0x436f7274
/* Bits */
/* RTC_SS_RTC_STATUS_REG */
#define RTC_BUSY_BIT 0
/* RTC_SS_RTC_CTRL_REG */
#define RTC_STOP_BIT 0
/* RTC_SS_RTC_SYSCONFIG */
#define NOIDLE_BIT 0
/* RTC_SS_RTC_OSC_REG */
#define EN_32KCLK_BIT 6
/* RTC_SS_RTC_PMIC */
#define PWR_ENABLE_EN_BIT 16
/* RTC_SS_RTC_INTERRUPTS_REG */
#define IT_ALARM2_BIT 4
/* Clocks */
#define CM_RTC_RTC_CLKCTRL 0x800
#define CM_RTC_RTC_CLKCTRL_IDLEST ((0<<17)|(0<<16))
#define CM_RTC_RTC_CLKCTRL_MODULEMODE ((1<<1)|(0<<0))
#define CM_RTC_RTC_CLKCTRL_MASK (CM_RTC_RTC_CLKCTRL_IDLEST|CM_RTC_RTC_CLKCTRL_MODULEMODE)
#define CM_RTC_CLKSTCTRL 0x804
#define CLKACTIVITY_RTC_32KCLK (1<<9)
#define CLKACTIVITY_L4_RTC_GCLK (1<<8)
#define CLKTRCTRL ((0<<1)|(0<<0))
#define CM_RTC_CLKSTCTRL_MASK (CLKACTIVITY_RTC_32KCLK|CLKACTIVITY_L4_RTC_GCLK|CLKTRCTRL)
int omap_rtc_init(void);
int omap_rtc_get_time(struct tm *t, int flags);
int omap_rtc_set_time(struct tm *t, int flags);
int omap_rtc_pwr_off(void);
void omap_rtc_exit(void);
#endif /* __OMAP_RTC_REGISTERS_H */

View File

@@ -1,6 +1,6 @@
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= cat24c256
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -14,7 +14,7 @@ SUBDIR+= rtl8169
SUBDIR+= virtio_net
.endif # ${MACHINE_ARCH} == "i386"
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= lan8710a
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -4,7 +4,7 @@
SUBDIR+= acpi
.endif # ${MACHINE_ARCH} == "i386"
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= tps65217
SUBDIR+= tps65950
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -1,6 +1,6 @@
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= bmp085
SUBDIR+= sht21
SUBDIR+= tsl2550

View File

@@ -2,7 +2,7 @@
PROG= mmc
SRCS= mmcblk.c mmchost_dummy.c sdhcreg.h sdmmcreg.h
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SRCS += mmchost_mmchs.c
.endif

View File

@@ -89,7 +89,7 @@ dir.acpi:= minix/drivers/power/acpi
.endif
.endif # ${MACHINE_ARCH} == "i386"
.if ${MACHINE_ARCH} == "earm"
.if ( (${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
PROGRAMS+= mmc
dir.mmc:= minix/drivers/storage/mmc
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -1,6 +1,6 @@
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= gpio
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -0,0 +1,7 @@
# Makefile for arch-dependent TTY code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS += console.c keyboard.c rs232.c

View File

@@ -0,0 +1,30 @@
/* Console unsupport for ARM. Just stubs. */
#include <minix/ipc.h>
#include <sys/termios.h>
#include "tty.h"
void
do_video(message *m, int ipc_status)
{
}
void
scr_init(tty_t *tp)
{
}
void
cons_stop(void)
{
}
void
beep_x(unsigned int freq, clock_t dur)
{
}
int
con_loadfont(endpoint_t endpt, cp_grant_id_t grant)
{
return 0;
}

View File

@@ -0,0 +1,30 @@
/* Keyboard unsupport for ARM. Just stubs. */
#include <minix/ipc.h>
#include <sys/termios.h>
#include "tty.h"
void
do_fkey_ctl(message *m)
{
}
void
do_input(message *m)
{
}
void
kb_init_once(void)
{
}
int
kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant)
{
return 0;
}
void
kb_init(tty_t *tp)
{
}

View File

@@ -0,0 +1,107 @@
#ifndef _OMAP_SERIAL_H
#define _OMAP_SERIAL_H
/* UART register map */
#define OMAP3_UART1_BASE 0x4806A000 /* UART1 physical address */
#define OMAP3_UART2_BASE 0x4806C000 /* UART2 physical address */
#define OMAP3_UART3_BASE 0x49020000 /* UART3 physical address */
/* UART registers */
#define OMAP3_THR 0 /* Transmit holding register */
#define OMAP3_RHR 0 /* Receive holding register */
#define OMAP3_DLL 0 /* Divisor latches low */
#define OMAP3_DLH 1 /* Divisor latches high */
#define OMAP3_IER 1 /* Interrupt enable register */
#define OMAP3_IIR 2 /* Interrupt identification register */
#define OMAP3_EFR 2 /* Extended features register */
#define OMAP3_FCR 2 /* FIFO control register */
#define OMAP3_LCR 3 /* Line control register */
#define OMAP3_MCR 4 /* Modem control register */
#define OMAP3_LSR 5 /* Line status register */
#define OMAP3_MSR 6 /* Modem status register */
#define OMAP3_TCR 6
#define OMAP3_MDR1 0x08 /* Mode definition register 1 */
#define OMAP3_MDR2 0x09 /* Mode definition register 2 */
#define OMAP3_SCR 0x10 /* Supplementary control register */
#define OMAP3_SSR 0x11 /* Supplementary status register */
#define OMAP3_SYSC 0x15 /* System configuration register */
#define OMAP3_SYSS 0x16 /* System status register */
/* Enhanced Features Register bits */
#define UART_EFR_ECB (1 << 4)/* Enhanced control bit */
#define UART_EFR_AUTO_CTS (1 << 6)/* auto cts enable */
#define UART_EFR_AUTO_RTS (1 << 7)/* auto rts enable */
/* Interrupt Enable Register bits */
#define UART_IER_MSI 0x08 /* Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Receiver data interrupt */
/* FIFO control register */
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
#define OMAP_UART_FCR_TX_FIFO_TRIG_SHIFT 4
#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4)
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the fifo */
#define UART_FCR_CLR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLR_XMIT 0x04 /* Clear the XMIT FIFO */
/* Interrupt Identification Register bits */
#define UART_IIR_RDI 0x04 /* Data ready interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_NO_INT 0x01 /* No interrupt is pending */
/* Line Control Register bits */
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Enable parity */
#define UART_LCR_STOP 0x04 /* Stop bits; 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN5 0x00 /* Wordlength 5 bits */
#define UART_LCR_WLEN6 0x01 /* Wordlength 6 bits */
#define UART_LCR_WLEN7 0x02 /* Wordlength 7 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength 8 bits */
#define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configuration Mode A */
#define UART_LCR_CONF_MODE_B 0xBF /* Configuration Mode B */
/* Line Status Register bits */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x10 /* Break condition */
#define UART_LSR_DR 0x01 /* Data ready */
/* Modem Control Register bits */
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR output low */
/* Mode Definition Register 1 bits */
#define OMAP_MDR1_DISABLE 0x07
#define OMAP_MDR1_MODE13X 0x03
#define OMAP_MDR1_MODE16X 0x00
/* Modem Status Register bits */
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
#define UART_MSR_CTS 0x10 /* Clear to Send */
#define UART_MSR_DDCD 0x08 /* Delta DCD */
/* Supplementary control Register bits */
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
/* System Control Register bits */
#define UART_SYSC_SOFTRESET 0x02
/* System Status Register bits */
#define UART_SYSS_RESETDONE 0x01
/* Line status register fields */
#define OMAP3_LSR_TX_FIFO_E (1 << 5) /* Transmit FIFO empty */
#define OMAP3_LSR_RX_FIFO_E (1 << 0) /* Receive FIFO empty */
#define OMAP3_LSR_RXOE (1 << 1) /* Overrun error.*/
/* Supplementary status register fields */
#define OMAP3_SSR_TX_FIFO_FULL (1 << 0) /* Transmit FIFO full */
#endif /* _OMAP_SERIAL_H */

View File

@@ -0,0 +1,848 @@
#include <minix/config.h>
#include <minix/drivers.h>
#include <minix/vm.h>
#include <minix/type.h>
#include <minix/board.h>
#include <sys/mman.h>
#include <assert.h>
#include <signal.h>
#include <termios.h>
#include "omap_serial.h"
#include "tty.h"
#if NR_RS_LINES > 0
#define UART_FREQ 48000000L /* timer frequency */
#if 0
#define DFLT_BAUD TSPEED_DEF /* default baud rate */
#else
#define DFLT_BAUD B115200 /* default baud rate */
#endif
#define RS_IBUFSIZE 40960 /* RS232 input buffer size */
#define RS_OBUFSIZE 40960 /* RS232 output buffer size */
/* Input buffer watermarks.
* The external device is asked to stop sending when the buffer
* exactly reaches high water, or when TTY requests it. Sending restarts
* when the input buffer empties below the low watermark.
*/
#define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
/* Output buffer low watermark.
* TTY is notified when the output buffer empties below the low watermark, so
* it may continue filling the buffer if doing a large write.
*/
#define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
/* Macros to handle flow control.
* Interrupts must be off when they are used.
* Time is critical - already the function call for outb() is annoying.
* If outb() can be done in-line, tests to avoid it can be dropped.
* istart() tells external device we are ready by raising RTS.
* istop() tells external device we are not ready by dropping RTS.
* DTR is kept high all the time (it probably should be raised by open and
* dropped by close of the device).
* OUT2 is also kept high all the time.
*/
#define istart(rs) \
(serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS|UART_MCR_DTR),\
(rs)->idevready = TRUE)
#define istop(rs) \
(serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_DTR), \
(rs)->idevready = FALSE)
/* Macro to tell if device is ready. The rs->cts field is set to UART_MSR_CTS
* if CLOCAL is in effect for a line without a CTS wire.
*/
#define devready(rs) ((serial_in(rs, OMAP3_MSR) | rs->cts) & UART_MSR_CTS)
/* Macro to tell if transmitter is ready. */
#define txready(rs) (serial_in(rs, OMAP3_LSR) & UART_LSR_THRE)
/* RS232 device structure, one per device. */
typedef struct rs232 {
tty_t *tty; /* associated TTY structure */
int icount; /* number of bytes in the input buffer */
char *ihead; /* next free spot in input buffer */
char *itail; /* first byte to give to TTY */
char idevready; /* nonzero if we are ready to receive (RTS) */
char cts; /* normally 0, but MS_CTS if CLOCAL is set */
unsigned char ostate; /* combination of flags: */
#define ODONE 1 /* output completed (< output enable bits) */
#define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
#define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
#define ODEVREADY UART_MSR_CTS /* external device hardware ready (CTS) */
#define OQUEUED 0x20 /* output buffer not empty */
#define OSWREADY 0x40 /* external device software ready (no xoff) */
#define ODEVHUP UART_MSR_DCD /* external device has dropped carrier */
#define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
/* user-defined bits */
#if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
/* a weak sanity check */
#error /* bits are not unique */
#endif
unsigned char oxoff; /* char to stop output */
char inhibited; /* output inhibited? (follows tty_inhibited) */
char drain; /* if set drain output and reconfigure line */
int ocount; /* number of bytes in the output buffer */
char *ohead; /* next free spot in output buffer */
char *otail; /* next char to output */
phys_bytes phys_base; /* UART physical base address (I/O map) */
unsigned int reg_offset; /* UART register offset */
unsigned int ier; /* copy of ier register */
unsigned int scr; /* copy of scr register */
unsigned int fcr; /* copy of fcr register */
unsigned int dll; /* copy of dll register */
unsigned int dlh; /* copy of dlh register */
unsigned int uartclk; /* UART clock rate */
unsigned char lstatus; /* last line status */
int rx_overrun_events;
int irq; /* irq for this line */
int irq_hook_id; /* interrupt hook */
int irq_hook_kernel_id; /* id as returned from sys_irqsetpolicy */
char ibuf[RS_IBUFSIZE]; /* input buffer */
char obuf[RS_OBUFSIZE]; /* output buffer */
} rs232_t;
static rs232_t rs_lines[NR_RS_LINES];
typedef struct uart_port {
phys_bytes base_addr;
int irq;
} uart_port_t;
/* OMAP3 UART base addresses. */
static uart_port_t dm37xx_ports[] = {
{ OMAP3_UART1_BASE, 72}, /* UART1 */
{ OMAP3_UART2_BASE, 73}, /* UART2 */
{ OMAP3_UART3_BASE, 74}, /* UART3 */
{ 0, 0 }
};
static uart_port_t am335x_ports[] = {
{ 0x44E09000 , 72 }, /* UART0 */
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
static int rs_write(tty_t *tp, int try);
static void rs_echo(tty_t *tp, int c);
static int rs_ioctl(tty_t *tp, int try);
static void rs_config(rs232_t *rs);
static int rs_read(tty_t *tp, int try);
static int rs_icancel(tty_t *tp, int try);
static int rs_ocancel(tty_t *tp, int try);
static void rs_ostart(rs232_t *rs);
static int rs_break_on(tty_t *tp, int try);
static int rs_break_off(tty_t *tp, int try);
static int rs_close(tty_t *tp, int try);
static int rs_open(tty_t *tp, int try);
static void rs232_handler(rs232_t *rs);
static void rs_reset(rs232_t *rs);
static unsigned int check_modem_status(rs232_t *rs);
static int termios_baud_rate(struct termios *term);
static inline unsigned int readw(vir_bytes addr);
static inline unsigned int serial_in(rs232_t *rs, int offset);
static inline void serial_out(rs232_t *rs, int offset, int val);
static inline void writew(vir_bytes addr, int val);
static void write_chars(rs232_t *rs);
static void read_chars(rs232_t *rs, unsigned int status);
static inline unsigned int
readw(vir_bytes addr)
{
return *((volatile unsigned int *) addr);
}
static inline void
writew(vir_bytes addr, int val)
{
*((volatile unsigned int *) addr) = val;
}
static inline unsigned int
serial_in(rs232_t *rs, int offset)
{
offset <<= rs->reg_offset;
return readw(rs->phys_base + offset);
}
static inline void
serial_out(rs232_t *rs, int offset, int val)
{
offset <<= rs->reg_offset;
writew(rs->phys_base + offset, val);
}
static void
rs_reset(rs232_t *rs)
{
u32_t syss;
serial_out(rs, OMAP3_SYSC, UART_SYSC_SOFTRESET);
/* Poll until done */
do {
syss = serial_in(rs, OMAP3_SYSS);
} while (!(syss & UART_SYSS_RESETDONE));
}
static int
rs_write(register tty_t *tp, int try)
{
/* (*devwrite)() routine for RS232. */
rs232_t *rs = tp->tty_priv;
int r, count, ocount;
if (rs->inhibited != tp->tty_inhibited) {
/* Inhibition state has changed. */
rs->ostate |= OSWREADY;
if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
rs->inhibited = tp->tty_inhibited;
}
if (rs->drain) {
/* Wait for the line to drain then reconfigure and continue
* output. */
if (rs->ocount > 0) return 0;
rs->drain = FALSE;
rs_config(rs);
}
/* While there is something to do. */
for (;;) {
ocount = buflen(rs->obuf) - rs->ocount;
count = bufend(rs->obuf) - rs->ohead;
if (count > ocount) count = ocount;
if (count > tp->tty_outleft) count = tp->tty_outleft;
if (count == 0 || tp->tty_inhibited) {
if (try) return 0;
break;
}
if (try) return 1;
/* Copy from user space to the RS232 output buffer. */
if (tp->tty_outcaller == KERNEL) {
/* We're trying to print on kernel's behalf */
memcpy(rs->ohead,
(char *) tp->tty_outgrant + tp->tty_outcum,
count);
} else {
if ((r = sys_safecopyfrom(tp->tty_outcaller,
tp->tty_outgrant, tp->tty_outcum,
(vir_bytes) rs->ohead, count)) != OK) {
return 0;
}
}
/* Perform output processing on the output buffer. */
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
&ocount);
if (count == 0) {
break;
}
/* Assume echoing messed up by output. */
tp->tty_reprint = TRUE;
/* Bookkeeping. */
rs->ocount += ocount;
rs_ostart(rs);
if ((rs->ohead += ocount) >= bufend(rs->obuf))
rs->ohead -= buflen(rs->obuf);
tp->tty_outcum += count;
if ((tp->tty_outleft -= count) == 0) {
/* Output is finished, reply to the writer. */
if (tp->tty_outcaller != KERNEL)
chardriver_reply_task(tp->tty_outcaller,
tp->tty_outid, tp->tty_outcum);
tp->tty_outcum = 0;
tp->tty_outcaller = NONE;
}
}
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
/* Oops, the line has hung up. */
if (tp->tty_outcaller != KERNEL)
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
EIO);
tp->tty_outleft = tp->tty_outcum = 0;
tp->tty_outcaller = NONE;
}
return 1;
}
static void
rs_echo(tty_t *tp, int character)
{
/* Echo one character. (Like rs_write, but only one character, optionally.) */
rs232_t *rs = tp->tty_priv;
int count, ocount;
ocount = buflen(rs->obuf) - rs->ocount;
if (ocount == 0) return; /* output buffer full */
count = 1;
*rs->ohead = character; /* add one character */
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
if (count == 0) return;
rs->ocount += ocount;
rs_ostart(rs);
if ((rs->ohead += ocount) >= bufend(rs->obuf))
rs->ohead -= buflen(rs->obuf);
}
static int
rs_ioctl(tty_t *tp, int UNUSED(dummy))
{
/* Reconfigure the line as soon as the output has drained. */
rs232_t *rs = tp->tty_priv;
rs->drain = TRUE;
return 0; /* dummy */
}
static unsigned int
omap_get_divisor(rs232_t *rs, unsigned int baud)
{
/* Calculate divisor value. The 16750 has two oversampling modes to reach
* high baud rates with little error rate (see table 17-1 in OMAP TRM).
* Baud rates 460800, 921600, 1843200, and 3686400 use 13x oversampling,
* the other rates 16x. The baud rate is calculated as follows:
* baud rate = (functional clock / oversampling) / divisor.
*/
unsigned int oversampling;
assert(baud != 0);
switch(baud) {
case B460800: /* Fall through */
case B921600: /* Fall through */
#if 0
case B1843200: /* Fall through */
case B3686400:
#endif
oversampling = 13; break;
default: oversampling = 16;
}
return (rs->uartclk / oversampling) / baud;
}
static int
termios_baud_rate(struct termios *term)
{
int baud;
switch(term->c_ospeed) {
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B0:
default:
/* Reset the speed to the default speed, then call ourselves
* to convert the default speed to a baudrate. This call will
* always return a value without inducing another recursive
* call. */
term->c_ospeed = DFLT_BAUD;
baud = termios_baud_rate(term);
}
return baud;
}
static void rs_config(rs232_t *rs)
{
/* Set various line control parameters for RS232 I/O. */
tty_t *tp = rs->tty;
unsigned int divisor, efr, lcr, mcr, baud;
/* Fifo and DMA settings */
/* See OMAP35x TRM 17.5.1.1.2 */
lcr = serial_in(rs, OMAP3_LCR); /* 1a */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 1b */
efr = serial_in(rs, OMAP3_EFR); /* 2a */
serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 2b */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 3 */
mcr = serial_in(rs, OMAP3_MCR); /* 4a */
serial_out(rs, OMAP3_MCR, mcr | UART_MCR_TCRTLR); /* 4b */
/* Set up FIFO */
rs->fcr = 0;
/* Set FIFO interrupt trigger levels high */
rs->fcr |= (0x3 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
rs->fcr |= (0x3 << OMAP_UART_FCR_TX_FIFO_TRIG_SHIFT);
rs->fcr |= UART_FCR_ENABLE_FIFO;
serial_out(rs, OMAP3_FCR, rs->fcr); /* 5 */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
/* DMA triggers, not supported by this driver */ /* 7 */
rs->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
serial_out(rs, OMAP3_SCR, rs->scr); /* 8 */
serial_out(rs, OMAP3_EFR, efr); /* 9 */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 10 */
serial_out(rs, OMAP3_MCR, mcr); /* 11 */
serial_out(rs, OMAP3_LCR, lcr); /* 12 */
/* RS232 needs to know the xoff character, and if CTS works. */
rs->oxoff = tp->tty_termios.c_cc[VSTOP];
rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? UART_MSR_CTS : 0;
baud = termios_baud_rate(&tp->tty_termios);
/* Look up the 16750 rate divisor from the output speed. */
divisor = omap_get_divisor(rs, baud);
rs->dll = divisor & 0xFF;
rs->dlh = divisor >> 8;
/* Compute line control flag bits. */
lcr = 0;
if (tp->tty_termios.c_cflag & PARENB) {
lcr |= UART_LCR_PARITY;
if (!(tp->tty_termios.c_cflag & PARODD)) lcr |= UART_LCR_EPAR;
}
if (tp->tty_termios.c_cflag & CSTOPB) lcr |= UART_LCR_STOP;
switch(tp->tty_termios.c_cflag & CSIZE) {
case CS5:
lcr |= UART_LCR_WLEN5;
break;
case CS6:
lcr |= UART_LCR_WLEN6;
break;
case CS7:
lcr |= UART_LCR_WLEN7;
break;
default:
case CS8:
lcr |= UART_LCR_WLEN8;
break;
}
/* Lock out interrupts while setting the speed. The receiver register
* is going to be hidden by the div_low register, but the input
* interrupt handler relies on reading it to clear the interrupt and
* avoid looping forever.
*/
if (sys_irqdisable(&rs->irq_hook_kernel_id) != OK)
panic("unable to disable interrupts");
/* Select the baud rate divisor registers and change the rate. */
/* See OMAP35x TRM 17.5.1.1.3 */
serial_out(rs, OMAP3_MDR1, OMAP_MDR1_DISABLE); /* 1 */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 2 */
efr = serial_in(rs, OMAP3_EFR); /* 3a */
serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 3b */
serial_out(rs, OMAP3_LCR, 0); /* 4 */
serial_out(rs, OMAP3_IER, 0); /* 5 */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
serial_out(rs, OMAP3_DLL, rs->dll); /* 7 */
serial_out(rs, OMAP3_DLH, rs->dlh); /* 7 */
serial_out(rs, OMAP3_LCR, 0); /* 8 */
serial_out(rs, OMAP3_IER, rs->ier); /* 9 */
serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 10 */
serial_out(rs, OMAP3_EFR, efr); /* 11 */
serial_out(rs, OMAP3_LCR, lcr); /* 12 */
if (baud > 230400 && baud != 3000000)
serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE13X); /* 13 */
else
serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE16X);
rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads MSR */
if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
rs->ostate &= ~ORAW;
(void) serial_in(rs, OMAP3_IIR);
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
panic("unable to enable interrupts");
}
void
rs_init(tty_t *tp)
{
/* Initialize RS232 for one line. */
register rs232_t *rs;
int line;
uart_port_t this_omap3;
char l[10];
struct minix_mem_range mr;
struct machine machine;
/* Associate RS232 and TTY structures. */
line = tp - &tty_table[NR_CONS];
/* See if kernel debugging is enabled; if so, don't initialize this
* serial line, making tty not look at the irq and returning ENXIO
* for all requests on it from userland. (The kernel will use it.)
*/
if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
printf("TTY: rs232 line %d not initialized (used by kernel)\n",
line);
return;
}
rs = tp->tty_priv = &rs_lines[line];
rs->tty = tp;
/* Set up input queue. */
rs->ihead = rs->itail = rs->ibuf;
sys_getmachine(&machine);
if (BOARD_IS_BBXM(machine.board_id)){
this_omap3 = dm37xx_ports[line];
} else if (BOARD_IS_BB(machine.board_id)){
this_omap3 = am335x_ports[line];
} else {
return;
}
if (this_omap3.base_addr == 0) return;
/* Configure memory access */
mr.mr_base = rs->phys_base;
mr.mr_limit = rs->phys_base + 0x100;
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to request access to UART memory");
}
rs->phys_base = (vir_bytes) vm_map_phys(SELF,
(void *) this_omap3.base_addr, 0x100);
if (rs->phys_base == (vir_bytes) MAP_FAILED) {
panic("Unable to request access to UART memory");
}
rs->reg_offset = 2;
rs->uartclk = UART_FREQ;
rs->ohead = rs->otail = rs->obuf;
/* Override system default baud rate. We do this because u-boot
* configures the UART for a baud rate of 115200 b/s and the kernel
* directly sends data over serial out upon boot up. If we then
* suddenly change the settings, the output will be garbled during
* booting.
*/
tp->tty_termios.c_ospeed = DFLT_BAUD;
/* Configure IRQ */
rs->irq = this_omap3.irq;
/* callback with irq line number + 1 because using line number 0
fails eslewhere */
rs->irq_hook_kernel_id = rs->irq_hook_id = line + 1;
/* sys_irqsetpolicy modifies irq_hook_kernel_id. this modified id
* needs to be used in sys_irqenable and similar calls.
*/
if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_kernel_id) != OK) {
printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
} else {
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK) {
printf("RS232: Couldn't enable irq %d (hooked)\n",
rs->irq);
}
}
/* When we get called back we get called back using the original
* hook_id bit set. e.g. if we register with hook_id 5 the callback
* calls us with the 5 th bit set */
rs_irq_set |= (1 << (rs->irq_hook_id ));
/* Enable interrupts */
rs_reset(rs);
rs->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_MSI;
rs_config(rs);
/* Fill in TTY function hooks. */
tp->tty_devread = rs_read;
tp->tty_devwrite = rs_write;
tp->tty_echo = rs_echo;
tp->tty_icancel = rs_icancel;
tp->tty_ocancel = rs_ocancel;
tp->tty_ioctl = rs_ioctl;
tp->tty_break_on = rs_break_on;
tp->tty_break_off = rs_break_off;
tp->tty_open = rs_open;
tp->tty_close = rs_close;
/* Tell external device we are ready. */
istart(rs);
}
void
rs_interrupt(message *m)
{
unsigned long irq_set;
int line;
rs232_t *rs;
irq_set = m->m_notify.interrupts;
for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
if (irq_set & (1 << rs->irq_hook_id)) {
rs232_handler(rs);
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
panic("unable to enable interrupts");
}
}
}
static int
rs_icancel(tty_t *tp, int UNUSED(dummy))
{
/* Cancel waiting input. */
rs232_t *rs = tp->tty_priv;
rs->icount = 0;
rs->itail = rs->ihead;
istart(rs);
return 0; /* dummy */
}
static int
rs_ocancel(tty_t *tp, int UNUSED(dummy))
{
/* Cancel pending output. */
rs232_t *rs = tp->tty_priv;
rs->ostate &= ~(ODONE | OQUEUED);
rs->ocount = 0;
rs->otail = rs->ohead;
return 0; /* dummy */
}
static int
rs_read(tty_t *tp, int try)
{
/* Process characters from the circular input buffer. */
rs232_t *rs = tp->tty_priv;
int icount, count, ostate;
if (!(tp->tty_termios.c_cflag & CLOCAL)) {
if (try) return 1;
/* Send a SIGHUP if hangup detected. */
ostate = rs->ostate;
rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
if (ostate & ODEVHUP) {
sigchar(tp, SIGHUP, 1);
tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
return 0;
}
}
if (try) {
return(rs->icount > 0);
}
while ((count = rs->icount) > 0) {
icount = bufend(rs->ibuf) - rs->itail;
if (count > icount) count = icount;
/* Perform input processing on (part of) the input buffer. */
if ((count = in_process(tp, rs->itail, count)) == 0) break;
rs->icount -= count;
if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
if ((rs->itail += count) == bufend(rs->ibuf))
rs->itail = rs->ibuf;
}
return 0;
}
static void
rs_ostart(rs232_t *rs)
{
/* Tell RS232 there is something waiting in the output buffer. */
rs->ostate |= OQUEUED;
if (txready(rs)) write_chars(rs);
}
static int
rs_break_on(tty_t *tp, int UNUSED(dummy))
{
/* Raise break condition */
rs232_t *rs = tp->tty_priv;
unsigned int lsr;
lsr = serial_in(rs, OMAP3_LSR);
serial_out(rs, OMAP3_LSR, lsr | UART_LSR_BI);
return 0; /* dummy */
}
static int
rs_break_off(tty_t *tp, int UNUSED(dummy))
{
/* Clear break condition */
rs232_t *rs = tp->tty_priv;
unsigned int lsr;
lsr = serial_in(rs, OMAP3_LSR);
serial_out(rs, OMAP3_LSR, lsr & ~UART_LSR_BI);
return 0; /* dummy */
}
static int
rs_open(tty_t *tp, int UNUSED(dummy))
{
/* Set the speed to 115200 by default */
tp->tty_termios.c_ospeed = DFLT_BAUD;
return 0;
}
static int
rs_close(tty_t *tp, int UNUSED(dummy))
{
/* The line is closed; optionally hang up. */
rs232_t *rs = tp->tty_priv;
if (tp->tty_termios.c_cflag & HUPCL) {
serial_out(rs, OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS);
if (rs->ier & UART_IER_THRI) {
rs->ier &= ~UART_IER_THRI;
serial_out(rs, OMAP3_IER, rs->ier);
}
}
return 0; /* dummy */
}
/* Low level (interrupt) routines. */
static void
rs232_handler(struct rs232 *rs)
{
/* Handle interrupt of a UART port */
unsigned int iir, lsr;
iir = serial_in(rs, OMAP3_IIR);
if (iir & UART_IIR_NO_INT) /* No interrupt */
return;
lsr = serial_in(rs, OMAP3_LSR);
if (iir & UART_IIR_RDI) { /* Data ready interrupt */
if (lsr & UART_LSR_DR) {
read_chars(rs, lsr);
}
}
check_modem_status(rs);
if (iir & UART_IIR_THRI) {
if (lsr & UART_LSR_THRE) {
/* Ready to send and space available */
write_chars(rs);
}
}
}
static void
read_chars(rs232_t *rs, unsigned int status)
{
unsigned char c;
if(serial_in(rs,OMAP3_LSR) & OMAP3_LSR_RXOE) {
rs->rx_overrun_events++;
}
/* check the line status to know if there are more chars */
while (serial_in(rs, OMAP3_LSR) & UART_LSR_DR) {
c = serial_in(rs, OMAP3_RHR);
if (!(rs->ostate & ORAW)) {
if (c == rs->oxoff) {
rs->ostate &= ~OSWREADY;
} else if (!(rs->ostate & OSWREADY)) {
rs->ostate = OSWREADY;
}
}
if (rs->icount == buflen(rs->ibuf)) {
/* no buffer space? keep reading */
continue;
}
if (++rs->icount == RS_IHIGHWATER && rs->idevready) {
istop(rs);
}
*rs->ihead = c;
if (++rs->ihead == bufend(rs->ibuf)) {
rs->ihead = rs->ibuf;
}
if (rs->icount == 1) {
rs->tty->tty_events = 1;
}
}
}
static void
write_chars(rs232_t *rs)
{
/* If there is output to do and everything is ready, do it (local device is
* known ready).
* Notify TTY when the buffer goes empty.
*/
if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
/* Bit test allows ORAW and requires the others. */
serial_out(rs, OMAP3_THR, *rs->otail);
if (++rs->otail == bufend(rs->obuf))
rs->otail = rs->obuf;
if (--rs->ocount == 0) {
/* Turn on ODONE flag, turn off OQUEUED */
rs->ostate ^= (ODONE | OQUEUED);
rs->tty->tty_events = 1;
if (rs->ier & UART_IER_THRI) {
rs->ier &= ~UART_IER_THRI;
serial_out(rs, OMAP3_IER, rs->ier);
}
} else {
if (rs->icount == RS_OLOWWATER)
rs->tty->tty_events = 1;
if (!(rs->ier & UART_IER_THRI)) {
rs->ier |= UART_IER_THRI;
serial_out(rs, OMAP3_IER, rs->ier);
}
}
}
}
static unsigned int
check_modem_status(rs232_t *rs)
{
/* Check modem status */
unsigned int msr;
msr = serial_in(rs, OMAP3_MSR); /* Resets modem interrupt */
if ((msr & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) {
rs->ostate |= ODEVHUP;
rs->tty->tty_events = 1;
}
if (!devready(rs))
rs->ostate &= ~ODEVREADY;
else
rs->ostate |= ODEVREADY;
return msr;
}
#endif /* NR_RS_LINES > 0 */

View File

@@ -1,6 +1,6 @@
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= usbd
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -1,7 +1,7 @@
# Makefile for usb host controllers
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR= .WAIT base/earm
.endif

View File

@@ -1,6 +1,6 @@
.include <bsd.own.mk>
.if ${MACHINE_ARCH} == "earm"
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= fb
SUBDIR+= tda19988
.endif # ${MACHINE_ARCH} == "earm"

View File

@@ -0,0 +1,7 @@
# Makefile for arch-dependent framebuffer code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS += fb_arch.c

View File

@@ -0,0 +1,65 @@
#ifndef __DSS_H__
#define __DSS_H__
/* DSS Base Registers */
#define OMAP3_DSS_BASE 0x48050000
#define OMAP3_DISPC_BASE 0x48050400
#define OMAP3_VENC_BASE 0x48050C00
#define OMAP3_DSS_SYSCONFIG(b) (b + 0x10)
#define OMAP3_DSS_SYSSTATUS(b) (b + 0x14)
#define OMAP3_DISPC_IRQSTATUS(b) (b + 0x18)
#define OMAP3_DISPC_CONTROL(b) (b + 0x40)
#define OMAP3_DISPC_CONFIG(b) (b + 0x44)
#define OMAP3_DISPC_DEFAULT_COLOR0(b) (b + 0x4c)
#define OMAP3_DISPC_DEFAULT_COLOR1(b) (b + 0x50)
#define OMAP3_DISPC_TIMINGH(b) (b + 0x64)
#define OMAP3_DISPC_TIMINGV(b) (b + 0x68)
#define OMAP3_DISPC_POL_FREQ(b) (b + 0x6c)
#define OMAP3_DISPC_DIVISOR(b) (b + 0x70)
#define OMAP3_DISPC_SIZE_DIG(b) (b + 0x78)
#define OMAP3_DISPC_SIZE_LCD(b) (b + 0x7c)
#define OMAP3_DISPC_GFX_BA0(b) (b + 0x80)
#define OMAP3_DISPC_GFX_BA1(b) (b + 0x84)
#define OMAP3_DISPC_GFX_SIZE(b) (b + 0x8c)
#define OMAP3_DISPC_GFX_ATTRIBUTES(b) (b + 0xa0)
#define OMAP3_DISPC_GFX_ROW_INC(b) (b + 0xac)
#define OMAP3_DISPC_GFX_PIXEL_INC(b) (b + 0xb0)
#define LOADMODE_SHIFT 1
#define TFTSTN_SHIFT 3
#define DATALINES_SHIFT 8
#define GFXFORMAT_SHIFT 1
#define GFXBURSTSIZE_SHIFT 6
#define DSS_SOFTRESET (1 << 1)
#define DSS_RESETDONE (1 << 0)
#define DISPC_LCDENABLE (1 << 0)
#define DISPC_DIGITALENABLE (1 << 1)
#define DISPC_GOLCD (1 << 5)
#define DISPC_GODIGITAL (1 << 6)
#define DISPC_GPIN0 (1 << 13)
#define DISPC_GPIN1 (1 << 14)
#define DISPC_GPOUT0 (1 << 15)
#define DISPC_GPOUT1 (1 << 16)
#define DISPC_ENABLESIGNAL (1 << 28)
#define DISPC_FRAMEDONE (1 << 0)
#define DISPC_GFXENABLE (1 << 0)
#define DISPC_GFXFORMAT_BMP1 0x0
#define DISPC_GFXFORMAT_BMP2 0x1
#define DISPC_GFXFORMAT_BMP4 0x2
#define DISPC_GFXFORMAT_BMP8 0x3
#define DISPC_GFXFORMAT_RGB12 0x4
#define DISPC_GFXFORMAT_ARGB16 0x5
#define DISPC_GFXFORMAT_RGB16 0x6
#define DISPC_GFXFORMAT_RGB24 0x8
#define DISPC_GFXFORMAT_RGB24P 0x9
#define DISPC_GFXFORMAT_ARGB32 0xC
#define DISPC_GFXFORMAT_RGBA32 0xD
#define DISPC_GFXFORMAT_RGBx 0xE
#define DISPC_GFXBURSTSIZE_4 0x0
#define DISPC_GFXBURSTSIZE_8 0x1
#define DISPC_GFXBURSTSIZE_16 0x2
#endif /* __DSS_H__ */

View File

@@ -0,0 +1,408 @@
/* Architecture dependent part for the framebuffer on the OMAP3.
* There's obvious room for improvement.
*/
#include <minix/chardriver.h>
#include <minix/drivers.h>
#include <minix/fb.h>
#include <minix/type.h>
#include <minix/vm.h>
#include <minix/log.h>
#include <assert.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <dev/videomode/videomode.h>
#include <dev/videomode/edidvar.h>
#include <dev/videomode/edidreg.h>
#include "dss.h"
#include "fb.h"
/* default / fallback resolution if EDID reading fails */
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 600
#define PAGES_NR 2
#define NSUPPORTED_MODES (4)
/* List of valid modes from TRM 7.1
* Other modes might work (like the default 1024x600), but no guarantees.
*/
struct supported_modes {
int hdisplay;
int vdisplay;
} omap_supported_modes[NSUPPORTED_MODES] = {
{ .hdisplay = 1024, .vdisplay = 768 }, /* XGA */
{ .hdisplay = 1280, .vdisplay = 800 }, /* WXGA */
{ .hdisplay = 1400, .vdisplay = 1050 }, /* SXGA+ */
{ .hdisplay = 1280, .vdisplay = 720 } /* HD 720p */
};
/* local function prototypes */
static struct videomode *choose_mode(struct edid_info *info);
static void configure_with_defaults(int minor);
static int configure_with_edid(int minor, struct edid_info *info);
/* globals */
static vir_bytes dss_phys_base; /* Address of dss phys memory map */
static vir_bytes dispc_phys_base; /* Address of dispc phys memory map */
static vir_bytes fb_vir;
static phys_bytes fb_phys;
static size_t fb_size;
static int initialized = 0;
struct panel_config {
u32_t timing_h;
u32_t timing_v;
u32_t pol_freq;
u32_t divisor;
u32_t lcd_size;
u32_t panel_type;
u32_t data_lines;
u32_t load_mode;
u32_t panel_color;
};
static const struct panel_config default_cfg = {
/* See OMAP TRM section 15.7 for the register values/encoding */
.timing_h = 0x1a4024c9, /* Horizontal timing */
.timing_v = 0x02c00509, /* Vertical timing */
.pol_freq = 0x00007028, /* Pol Freq */
.divisor = 0x00010001, /* 96MHz Pixel Clock */
.lcd_size = ((SCREEN_HEIGHT - 1) << 16 | (SCREEN_WIDTH - 1)),
.panel_type = 0x01, /* TFT */
.data_lines = 0x03, /* 24 Bit RGB */
.load_mode = 0x02, /* Frame Mode */
.panel_color = 0xFFFFFF /* WHITE */
};
static struct panel_config omap_cfg[FB_DEV_NR];
static const struct fb_fix_screeninfo default_fbfs = {
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = SCREEN_WIDTH * 4,
.mmio_start = 0, /* Not implemented for char. special, so */
.mmio_len = 0 /* these are set to 0 */
};
static struct fb_fix_screeninfo omap_fbfs[FB_DEV_NR];
static const struct fb_var_screeninfo default_fbvs = {
.xres = SCREEN_WIDTH,
.yres = SCREEN_HEIGHT,
.xres_virtual = SCREEN_WIDTH,
.yres_virtual = SCREEN_HEIGHT*2,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 32,
.red = {
.offset = 16,
.length = 8,
.msb_right = 0
},
.green = {
.offset = 8,
.length = 8,
.msb_right = 0
},
.blue = {
.offset = 0,
.length = 8,
.msb_right = 0
},
.transp = {
.offset = 24,
.length = 8,
.msb_right = 0
}
};
static struct fb_var_screeninfo omap_fbvs[FB_DEV_NR];
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
static struct log log = {
.name = "fb",
.log_level = LEVEL_INFO,
.log_func = default_log
};
static inline u32_t
readw(vir_bytes addr)
{
return *((volatile u32_t *) addr);
}
static inline void
writew(vir_bytes addr, u32_t val)
{
*((volatile u32_t *) addr) = val;
}
static struct videomode *
choose_mode(struct edid_info *info)
{
int i, j;
/* choose the highest resolution supported by both the SoC and screen */
for (i = info->edid_nmodes - 1; i >= 0; i--) {
for (j = NSUPPORTED_MODES - 1; j >= 0; j--) {
if (info->edid_modes[i].hdisplay ==
omap_supported_modes[j].hdisplay &&
info->edid_modes[i].vdisplay ==
omap_supported_modes[j].vdisplay) {
return &(info->edid_modes[i]);
}
}
}
return NULL;
}
static int
configure_with_edid(int minor, struct edid_info *info)
{
struct videomode *mode;
if (info == NULL || minor < 0 || minor >= FB_DEV_NR) {
log_warn(&log, "Invalid minor #%d or info == NULL\n", minor);
return -1;
}
/* If debugging or tracing, print the contents of info */
if (log.log_level >= LEVEL_DEBUG) {
log_debug(&log, "--- EDID - START ---\n");
edid_print(info);
log_debug(&log, "--- EDID - END ---\n");
}
/* Choose the preferred mode. */
mode = choose_mode(info);
if (mode == NULL) {
log_warn(&log, "Couldn't find a supported resolution.\n");
return -1;
}
/*
* apply the default settings since we don't overwrite every field
*/
configure_with_defaults(minor);
/*
* apply the settings corresponding to the given EDID
*/
/* panel_config */
omap_cfg[minor].lcd_size = ((mode->vdisplay - 1) << 16 | (mode->hdisplay - 1));
if (EDID_FEATURES_DISP_TYPE(info->edid_features) ==
EDID_FEATURES_DISP_TYPE_MONO) {
omap_cfg[minor].panel_type = 0x00; /* Mono */
} else {
omap_cfg[minor].panel_type = 0x01; /* RGB/Color */
}
/* fb_fix_screeninfo */
omap_fbfs[minor].line_length = mode->hdisplay * 4;
/* fb_var_screeninfo */
omap_fbvs[minor].xres = mode->hdisplay;
omap_fbvs[minor].yres = mode->vdisplay;
omap_fbvs[minor].xres_virtual = mode->hdisplay;
omap_fbvs[minor].yres_virtual = mode->vdisplay*2;
return OK;
}
static void
configure_with_defaults(int minor)
{
if (minor < 0 || minor >= FB_DEV_NR) {
log_warn(&log, "Invalid minor #%d\n", minor);
return;
}
/* copy the default values into this minor's configuration */
memcpy(&omap_cfg[minor], &default_cfg, sizeof(struct panel_config));
memcpy(&omap_fbfs[minor], &default_fbfs, sizeof(struct fb_fix_screeninfo));
memcpy(&omap_fbvs[minor], &default_fbvs, sizeof(struct fb_var_screeninfo));
}
static void
arch_configure_display(int minor)
{
/* Tell hardware where frame buffer is and turn display on */
u32_t off, rdispc;
if (!initialized) return;
if (minor != 0) return;
off = omap_fbvs[minor].yoffset * omap_fbvs[minor].xres_virtual * (omap_fbvs[minor].bits_per_pixel/8);
writew((vir_bytes) OMAP3_DISPC_GFX_BA0(dispc_phys_base),
fb_phys + (phys_bytes) off);
rdispc = readw((vir_bytes) OMAP3_DISPC_CONTROL(dispc_phys_base));
rdispc |= DISPC_LCDENABLE | DISPC_DIGITALENABLE | DISPC_GOLCD |
DISPC_GODIGITAL | DISPC_GPOUT0 | DISPC_GPOUT1;
writew((vir_bytes) OMAP3_DISPC_CONTROL(dispc_phys_base), rdispc);
}
int
arch_get_device(int minor, struct device *dev)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
dev->dv_base = fb_vir;
dev->dv_size = fb_size;
return OK;
}
int
arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
*fbvsp = omap_fbvs[minor];
return OK;
}
int
arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
{
int r = OK;
assert(fbvsp != NULL);
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
/* For now we only allow to play with the yoffset setting */
if (fbvsp->yoffset != omap_fbvs[minor].yoffset) {
if (fbvsp->yoffset < 0 || fbvsp->yoffset > omap_fbvs[minor].yres) {
return EINVAL;
}
omap_fbvs[minor].yoffset = fbvsp->yoffset;
}
/* Now update hardware with new settings */
arch_configure_display(minor);
return OK;
}
int
arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
*fbfsp = omap_fbfs[minor];
return OK;
}
int
arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp)
{
return arch_put_varscreeninfo(minor, fbvsp);
}
int
arch_fb_init(int minor, struct edid_info *info)
{
int r;
u32_t rdispc;
struct minix_mem_range mr;
const struct panel_config *panel_cfg = &omap_cfg[minor];
if (minor != 0) return ENXIO; /* We support only one minor */
if (initialized) {
return OK;
} else if (info != NULL) {
log_debug(&log, "Configuring Settings based on EDID...\n");
r = configure_with_edid(minor, info);
if (r != OK) {
log_warn(&log, "EDID config failed. Using defaults.\n");
configure_with_defaults(minor);
}
} else {
log_debug(&log, "Loading Default Settings...\n");
configure_with_defaults(minor);
}
initialized = 1;
/* Configure DSS memory access */
mr.mr_base = OMAP3_DSS_BASE;
mr.mr_limit = mr.mr_base + 0x60;
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to request access to DSS(1) memory");
}
dss_phys_base = (vir_bytes) vm_map_phys(SELF, (void *) OMAP3_DSS_BASE,
0x60);
if (dss_phys_base == (vir_bytes) MAP_FAILED) {
panic("Unable to request access to DSS(2) memory");
}
/* Configure DISPC memory access */
mr.mr_base = OMAP3_DISPC_BASE;
mr.mr_limit = mr.mr_base + 0x430;
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to request access to DISPC(1) memory");
}
dispc_phys_base = (vir_bytes) vm_map_phys(SELF,
(void *) OMAP3_DISPC_BASE,
0x430);
if (dispc_phys_base == (vir_bytes) MAP_FAILED) {
panic("Unable to request access to DISPC(2) memory");
}
/* Set timings, screen mode, screen size, etc. */
writew(OMAP3_DISPC_TIMINGH(dispc_phys_base), panel_cfg->timing_h);
writew(OMAP3_DISPC_TIMINGV(dispc_phys_base), panel_cfg->timing_v);
writew(OMAP3_DISPC_POL_FREQ(dispc_phys_base), panel_cfg->pol_freq);
writew(OMAP3_DISPC_DIVISOR(dispc_phys_base), panel_cfg->divisor);
writew(OMAP3_DISPC_CONFIG(dispc_phys_base),
panel_cfg->load_mode << LOADMODE_SHIFT);
writew(OMAP3_DISPC_CONTROL(dispc_phys_base),
panel_cfg->panel_type << TFTSTN_SHIFT |
panel_cfg->data_lines << DATALINES_SHIFT);
writew((vir_bytes) OMAP3_DISPC_SIZE_LCD(dispc_phys_base),
panel_cfg->lcd_size);
writew((vir_bytes) OMAP3_DISPC_GFX_SIZE(dispc_phys_base),
panel_cfg->lcd_size);
writew(OMAP3_DISPC_DEFAULT_COLOR0(dispc_phys_base),
panel_cfg->panel_color);
/* Enable gfx engine */
writew(OMAP3_DISPC_GFX_ATTRIBUTES(dispc_phys_base),
(DISPC_GFXBURSTSIZE_16 << GFXBURSTSIZE_SHIFT) |
(DISPC_GFXFORMAT_RGB24 << GFXFORMAT_SHIFT) |
(DISPC_GFXENABLE));
writew(OMAP3_DISPC_GFX_ROW_INC(dispc_phys_base), 1);
writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base), 1);
/* Allocate contiguous physical memory for the display buffer */
fb_size = omap_fbvs[minor].yres_virtual * omap_fbvs[minor].xres_virtual *
(omap_fbvs[minor].bits_per_pixel / 8);
fb_vir = (vir_bytes) alloc_contig(fb_size, 0, &fb_phys);
if (fb_vir == (vir_bytes) MAP_FAILED) {
panic("Unable to allocate contiguous memory\n");
}
/* Configure buffer settings and turn on LCD/Digital */
arch_configure_display(minor);
return OK;
}

View File

@@ -0,0 +1,4 @@
SUBDIR= include
.include <bsd.subdir.mk>

View File

@@ -0,0 +1,8 @@
INCSDIR= /usr/include/arm
INCS= archconst.h archtypes.h diskparm.h elf.h interrupt.h \
ipcconst.h memory.h multiboot.h partition.h \
stackframe.h vm.h
.include <bsd.kinc.mk>

View File

@@ -0,0 +1,6 @@
#ifndef _ARM_CONST_H
#define _ARM_CONST_H
#define DEFAULT_HZ 1000
#endif /* #ifndef _ARM_CONST_H */

View File

@@ -0,0 +1,27 @@
#ifndef _ARM_TYPES_H
#define _ARM_TYPES_H
#include <minix/sys_config.h>
#include <machine/stackframe.h>
#include <sys/cdefs.h>
typedef struct segframe {
reg_t p_ttbr; /* page table root */
u32_t *p_ttbr_v;
char *fpu_state;
} segframe_t;
struct cpu_info {
u32_t arch;
u32_t implementer;
u32_t part;
u32_t variant;
u32_t freq; /* in MHz */
u32_t revision;
};
typedef u32_t atomic_t; /* access to an aligned 32bit value is atomic on ARM */
#endif /* #ifndef _ARM_TYPES_H */

View File

@@ -0,0 +1,20 @@
/* PC (and AT) BIOS structure to hold disk parameters. Under Minix, it is
* used mainly for formatting.
*/
#ifndef _DISKPARM_H
#define _DISKPARM_H
struct disk_parameter_s {
char spec1;
char spec2;
char motor_turnoff_sec;
char sector_size_code;
char sectors_per_cylinder;
char gap_length;
char dtl;
char gap_length_for_format;
char fill_byte_for_format;
char head_settle_msec;
char motor_start_eigth_sec;
};
#endif /* _DISKPARM_H */

View File

@@ -0,0 +1,42 @@
/*-
* Copyright (c) 1996-1997 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _MACHINE_ELF_H_
#define _MACHINE_ELF_H_ 1
/*
* ELF definitions for the ARM architecture.
*/
/* Define "machine" characteristics */
#define ELF_TARG_CLASS ELFCLASS32
#define ELF_TARG_DATA ELFDATA2LSB
#define ELF_TARG_MACH EM_ARM
#define ELF_TARG_VER 1
#endif /* !_MACHINE_ELF_H_ */

View File

@@ -0,0 +1,8 @@
/* Interrupt numbers and hardware vectors. */
#ifndef _INTERRUPT_H
#define _INTERRUPT_H
#define NR_IRQ_VECTORS 125
#endif /* _INTERRUPT_H */

View File

@@ -0,0 +1,9 @@
#ifndef _ARM_IPCCONST_H_
#define _ARM_IPCCONST_H_
#define KERVEC_INTR 32 /* syscall trap to kernel */
#define IPCVEC_INTR 33 /* ipc trap to kernel */
#define IPC_STATUS_REG r1
#endif /* _ARM_IPCCONST_H_ */

View File

@@ -0,0 +1,10 @@
/* Physical memory layout */
#ifndef _ARM_MEMORY_H
#define _ARM_MEMORY_H
/* omap */
#define PHYS_MEM_BEGIN 0x80000000
#define PHYS_MEM_END 0xbfffffff
#endif /* _ARM_MEMORY_H */

View File

@@ -0,0 +1,351 @@
/* $NetBSD: multiboot.h,v 1.8 2009/02/22 18:05:42 ahoka Exp $ */
/*-
* Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Julio M. Merino Vidal.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MULTIBOOT_H__
#define __MULTIBOOT_H__
#if !defined(_KERNEL) && defined(_STANDALONE)
/* --------------------------------------------------------------------- */
/*
* Multiboot header structure.
*/
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
#define MULTIBOOT_HEADER_MODS_ALIGNED 0x00000001
#define MULTIBOOT_HEADER_WANT_MEMORY 0x00000002
#define MULTIBOOT_HEADER_HAS_VBE 0x00000004
#define MULTIBOOT_HEADER_HAS_ADDR 0x00010000
#if !defined(_LOCORE)
struct multiboot_header {
uint32_t mh_magic;
uint32_t mh_flags;
uint32_t mh_checksum;
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
paddr_t mh_header_addr;
paddr_t mh_load_addr;
paddr_t mh_load_end_addr;
paddr_t mh_bss_end_addr;
paddr_t mh_entry_addr;
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. */
uint32_t mh_mode_type;
uint32_t mh_width;
uint32_t mh_height;
uint32_t mh_depth;
};
#endif /* !defined(_LOCORE) */
/*
* Symbols defined in locore.S.
*/
#if !defined(_LOCORE) && defined(_KERNEL)
extern struct multiboot_header *Multiboot_Header;
#endif /* !defined(_LOCORE) && defined(_KERNEL) */
/* --------------------------------------------------------------------- */
/*
* Multiboot information structure.
*/
#define MULTIBOOT_INFO_MAGIC 0x2BADB002
#define MULTIBOOT_INFO_HAS_MEMORY 0x00000001
#define MULTIBOOT_INFO_HAS_BOOT_DEVICE 0x00000002
#define MULTIBOOT_INFO_HAS_CMDLINE 0x00000004
#define MULTIBOOT_INFO_HAS_MODS 0x00000008
#define MULTIBOOT_INFO_HAS_AOUT_SYMS 0x00000010
#define MULTIBOOT_INFO_HAS_ELF_SYMS 0x00000020
#define MULTIBOOT_INFO_HAS_MMAP 0x00000040
#define MULTIBOOT_INFO_HAS_DRIVES 0x00000080
#define MULTIBOOT_INFO_HAS_CONFIG_TABLE 0x00000100
#define MULTIBOOT_INFO_HAS_LOADER_NAME 0x00000200
#define MULTIBOOT_INFO_HAS_APM_TABLE 0x00000400
#define MULTIBOOT_INFO_HAS_VBE 0x00000800
#if !defined(_LOCORE)
struct multiboot_info {
uint32_t mi_flags;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MEMORY. */
uint32_t mi_mem_lower;
uint32_t mi_mem_upper;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_BOOT_DEVICE. */
uint8_t mi_boot_device_part3;
uint8_t mi_boot_device_part2;
uint8_t mi_boot_device_part1;
uint8_t mi_boot_device_drive;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CMDLINE. */
char * mi_cmdline;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MODS. */
uint32_t mi_mods_count;
vaddr_t mi_mods_addr;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_{AOUT,ELF}_SYMS. */
uint32_t mi_elfshdr_num;
uint32_t mi_elfshdr_size;
vaddr_t mi_elfshdr_addr;
uint32_t mi_elfshdr_shndx;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MMAP. */
uint32_t mi_mmap_length;
vaddr_t mi_mmap_addr;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_DRIVES. */
uint32_t mi_drives_length;
vaddr_t mi_drives_addr;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CONFIG_TABLE. */
void * unused_mi_config_table;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_LOADER_NAME. */
char * mi_loader_name;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_APM. */
void * unused_mi_apm_table;
/* Valid if mi_flags sets MULTIBOOT_INFO_HAS_VBE. */
void * unused_mi_vbe_control_info;
void * unused_mi_vbe_mode_info;
paddr_t unused_mi_vbe_interface_seg;
paddr_t unused_mi_vbe_interface_off;
uint32_t unused_mi_vbe_interface_len;
};
/* --------------------------------------------------------------------- */
/*
* Drive information. This describes an entry in the drives table as
* pointed to by mi_drives_addr.
*/
struct multiboot_drive {
uint32_t md_length;
uint8_t md_number;
uint8_t md_mode;
uint16_t md_cylinders;
uint8_t md_heads;
uint8_t md_sectors;
/* The variable-sized 'ports' field comes here, so this structure
* can be longer. */
};
/* --------------------------------------------------------------------- */
/*
* Memory mapping. This describes an entry in the memory mappings table
* as pointed to by mi_mmap_addr.
*
* Be aware that mm_size specifies the size of all other fields *except*
* for mm_size. In order to jump between two different entries, you
* have to count mm_size + 4 bytes.
*/
struct multiboot_mmap {
uint32_t mm_size;
uint64_t mm_base_addr;
uint64_t mm_length;
uint32_t mm_type;
};
/*
* Modules. This describes an entry in the modules table as pointed
* to by mi_mods_addr.
*/
struct multiboot_module {
uint32_t mmo_start;
uint32_t mmo_end;
char * mmo_string;
uint32_t mmo_reserved;
};
#endif /* !defined(_LOCORE) */
/* --------------------------------------------------------------------- */
/*
* Prototypes for public functions defined in multiboot.c.
*/
#if !defined(_LOCORE) && defined(_KERNEL)
void multiboot_pre_reloc(struct multiboot_info *);
void multiboot_post_reloc(void);
void multiboot_print_info(void);
bool multiboot_ksyms_addsyms_elf(void);
#endif /* !defined(_LOCORE) */
/* --------------------------------------------------------------------- */
#else /* !defined(_KERNEL) && defined(_STANDALONE) */
/* LSC FIXME: OLD MINIX DEFINITION: should be removed and replace with
definition above... */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Must pass memory information to OS. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
#define MULTIBOOT_MEMORY_INFO 0x00000002
#define MULTIBOOT_VIDEO_MODE 0x00000004
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* consts used for Multiboot pre-init */
#define MULTIBOOT_VIDEO_MODE_EGA 1
#define MULTIBOOT_VIDEO_BUFFER 0xB8000
/* Usable lower memory chunk has a upper bound */
#define MULTIBOOT_LOWER_MEM_MAX 0x7f800
#define MULTIBOOT_CONSOLE_LINES 25
#define MULTIBOOT_CONSOLE_COLS 80
#define MULTIBOOT_VIDEO_BUFFER_BYTES \
(MULTIBOOT_CONSOLE_LINES*MULTIBOOT_CONSOLE_COLS*2)
#define MULTIBOOT_STACK_SIZE 4096
#define MULTIBOOT_PARAM_BUF_SIZE 1024
#define MULTIBOOT_MAX_MODS 20
/* Flags to be set in the flags member of the multiboot info structure. */
#define MULTIBOOT_INFO_MEMORY 0x00000001
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* Is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* Are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
#define MULTIBOOT_HIGH_MEM_BASE 0x100000
#ifndef __ASSEMBLY__
#include <sys/types.h>
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
u32_t tabsize;
u32_t strsize;
u32_t addr;
u32_t reserved;
};
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
u32_t num;
u32_t size;
u32_t addr;
u32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
struct multiboot_info
{
/* Multiboot info version number */
u32_t flags;
/* Available memory from BIOS */
u32_t mem_lower_unused; /* minix uses memmap instead */
u32_t mem_upper_unused;
/* "root" partition */
u32_t boot_device;
/* Kernel command line */
u32_t cmdline;
/* Boot-Module list */
u32_t mi_mods_count;
u32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
u32_t mmap_length;
u32_t mmap_addr;
/* Drive Info buffer */
u32_t drives_length;
u32_t drives_addr;
/* ROM configuration table */
u32_t config_table;
/* Boot Loader Name */
u32_t boot_loader_name;
/* APM table */
u32_t apm_table;
/* Video */
u32_t vbe_control_info;
u32_t vbe_mode_info;
u16_t vbe_mode;
u16_t vbe_interface_seg;
u16_t vbe_interface_off;
u16_t vbe_interface_len;
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_mod_list
{
/* Memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
u32_t mod_start;
u32_t mod_end;
/* Module command line */
u32_t cmdline;
/* Pad struct to 16 bytes (must be zero) */
u32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
struct multiboot_mmap_entry
{
u32_t size;
u64_t mm_base_addr;
u64_t mm_length;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
u32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
#endif /* __ASSEMBLY__ */
#endif /* !defined(_KERNEL) && defined(_STANDALONE) */
#endif /* __MULTIBOOT_H__ */

View File

@@ -0,0 +1,28 @@
/* Description of entry in partition table. */
#ifndef _PARTITION_H
#define _PARTITION_H
#include <stdint.h>
struct part_entry {
uint8_t bootind; /* boot indicator 0/ACTIVE_FLAG */
uint8_t start_head; /* head value for first sector */
uint8_t start_sec; /* sector value + cyl bits for first sector */
uint8_t start_cyl; /* track value for first sector */
uint8_t sysind; /* system indicator */
uint8_t last_head; /* head value for last sector */
uint8_t last_sec; /* sector value + cyl bits for last sector */
uint8_t last_cyl; /* track value for last sector */
uint32_t lowsec; /* logical first sector */
uint32_t size; /* size of partition in sectors */
};
#define ACTIVE_FLAG 0x80 /* value for active in bootind field (hd0) */
#define NR_PARTITIONS 4 /* number of entries in partition table */
#define PART_TABLE_OFF 0x1BE /* offset of partition table in boot sector */
/* Partition types. */
#define NO_PART 0x00 /* unused entry */
#define MINIX_PART 0x81 /* Minix partition type */
#endif /* _PARTITION_H */

View File

@@ -0,0 +1,28 @@
#ifndef _ARM_STACKFRAME_H
#define _ARM_STACKFRAME_H
#include <sys/types.h>
typedef u32_t reg_t; /* machine register */
struct stackframe_s {
reg_t retreg; /* r0 */
reg_t r1;
reg_t r2;
reg_t r3;
reg_t r4;
reg_t r5;
reg_t r6;
reg_t r7;
reg_t r8;
reg_t r9; /* sb */
reg_t r10; /* sl */
reg_t fp; /* r11 */
reg_t r12; /* ip */
reg_t sp; /* r13 */
reg_t lr; /* r14 */
reg_t pc; /* r15 */
reg_t psr;
};
#endif /* _ARM_STACKFRAME_H */

View File

@@ -0,0 +1,196 @@
#ifndef __SYS_VM_ARM_H__
#define __SYS_VM_ARM_H__
/*
arm/vm.h
*/
/*
* We are using the following setup
* the system is configured to have the TRE (Tex remap enable bit) set to 0
* The TEX[2:0] B and C bits are used to determins memory attributes.
* These bits together with the S Bit (Shareability Bit) determines the
* memory attributes.
*
* The S bit is ignored when the other attribute define the memory as
* "device" or "strongly ordered"
*
* We are setting the tex[2] bit to one to end up with the following
* encoding
*
* 00 00 Non cacheable
* 01 01 Write back, Write allocate
* 10 10 Write trough, No write allocate
* 11 11 Write back , Write alloc
*/
#define ARM_PAGE_SIZE 4096 /* small page on ARM */
#define ARM_SECTION_SIZE (1024 * 1024) /* 1 MB section */
/* Second level page table entries */
#define ARM_VM_PAGETABLE (1 << 1) /* Page table */
#define ARM_VM_PTE_PRESENT (1 << 1) /* Page is present */
#define ARM_VM_PTE_B (1 << 2) /* B bit */
#define ARM_VM_PTE_C (1 << 3) /* C bit */
#define ARM_VM_PTE_SUPER (0x1 << 4) /* Super access only AP[1:0] */
#define ARM_VM_PTE_USER (0x3 << 4) /* Super/User access AP[1:0] */
#define ARM_VM_PTE_TEX0 (1 << 6) /* TEX[0] */
#define ARM_VM_PTE_TEX1 (1 << 7) /* TEX[1] */
#define ARM_VM_PTE_TEX2 (1 << 8) /* TEX[2] */
#define ARM_VM_PTE_RO (1 << 9) /* Read only access AP[2] */
#define ARM_VM_PTE_RW (0 << 9) /* Read-write access AP[2] */
#define ARM_VM_PTE_S (1 << 10) /* "Shareable" */
#define ARM_VM_PTE_NOTGLOBAL (1 << 11) /* Not Global */
/* inner and outer write-back, write-allocate */
#define ARM_VM_PTE_WB (ARM_VM_PTE_TEX2 | ARM_VM_PTE_TEX0 | ARM_VM_PTE_B)
/* inner and outer write-through, no write-allocate */
#define ARM_VM_PTE_WT (ARM_VM_PTE_TEX2 | ARM_VM_PTE_TEX1 | ARM_VM_PTE_C )
/* Inner , Write through, No Write Allocate Outer - Write Back, Write Allocate */
#define ARM_VM_PTE_WTWB (ARM_VM_PTE_TEX2 | ARM_VM_PTE_TEX0 | ARM_VM_PTE_C )
#define ARM_VM_PTE_CACHED ARM_VM_PTE_WTWB
/* shareable device */
#define ARM_VM_PTE_DEVICE (ARM_VM_PTE_B)
#define ARM_VM_ADDR_MASK 0xFFFFF000 /* physical address */
#define ARM_VM_ADDR_MASK_1MB 0xFFF00000 /* physical address */
#define ARM_VM_OFFSET_MASK_1MB 0x000FFFFF /* physical address */
/* Big page (1MB section) specific flags. */
#define ARM_VM_SECTION (1 << 1) /* 1MB section */
#define ARM_VM_SECTION_PRESENT (1 << 1) /* Section is present */
#define ARM_VM_SECTION_B (1 << 2) /* B Bit */
#define ARM_VM_SECTION_C (1 << 3) /* C Bit */
#define ARM_VM_SECTION_DOMAIN (0xF << 5) /* Domain Number */
#define ARM_VM_SECTION_SUPER (0x1 << 10) /* Super access only AP[1:0] */
#define ARM_VM_SECTION_USER (0x3 << 10) /* Super/User access AP[1:0] */
#define ARM_VM_SECTION_TEX0 (1 << 12) /* TEX[0] */
#define ARM_VM_SECTION_TEX1 (1 << 13) /* TEX[1] */
#define ARM_VM_SECTION_TEX2 (1 << 14) /* TEX[2] */
#define ARM_VM_SECTION_RO (1 << 15) /* Read only access AP[2] */
#define ARM_VM_SECTION_SHAREABLE (1 << 16) /* Shareable */
#define ARM_VM_SECTION_NOTGLOBAL (1 << 17) /* Not Global */
/* inner and outer write-back, write-allocate */
#define ARM_VM_SECTION_WB (ARM_VM_SECTION_TEX2 | ARM_VM_SECTION_TEX0 | ARM_VM_SECTION_B )
/* inner and outer write-through, no write-allocate */
#define ARM_VM_SECTION_WT (ARM_VM_SECTION_TEX2 | ARM_VM_SECTION_TEX1 | ARM_VM_SECTION_C )
/* Inner , Write through, No Write Allocate Outer - Write Back, Write Allocate */
#define ARM_VM_SECTION_WTWB (ARM_VM_SECTION_TEX2 | ARM_VM_SECTION_TEX0 | ARM_VM_SECTION_C )
/* shareable device */
#define ARM_VM_SECTION_CACHED ARM_VM_SECTION_WTWB
#define ARM_VM_SECTION_DEVICE (ARM_VM_SECTION_B)
/* Page directory specific flags. */
#define ARM_VM_PAGEDIR (1 << 0) /* Page directory */
#define ARM_VM_PDE_PRESENT (1 << 0) /* Page directory is present */
#define ARM_VM_PDE_DOMAIN (0xF << 5) /* Domain Number */
#define ARM_VM_PT_ENT_SIZE 4 /* Size of a page table entry */
#define ARM_VM_DIR_ENT_SIZE 4 /* Size of a page dir entry */
#define ARM_VM_DIR_ENTRIES 4096 /* Number of entries in a page dir */
#define ARM_VM_DIR_ENT_SHIFT 20 /* Shift to get entry in page dir. */
#define ARM_VM_PT_ENT_SHIFT 12 /* Shift to get entry in page table */
#define ARM_VM_PT_ENT_MASK 0xFF /* Mask to get entry in page table */
#define ARM_VM_PT_ENTRIES 256 /* Number of entries in a page table */
#define ARM_VM_PTE(v) (((v) >> ARM_VM_PT_ENT_SHIFT) & ARM_VM_PT_ENT_MASK)
#define ARM_VM_PDE(v) ( (v) >> ARM_VM_DIR_ENT_SHIFT)
#define ARM_VM_PFA(e) ( (e) & ARM_VM_ADDR_MASK)
/* Second level small pages entry(Page Table Entry) points to 4K */
#define ARM_VM_PTE_SHIFT 12
#define ARM_VM_PTE_MASK (~((1 << ARM_VM_PTE_SHIFT) - 1))
/* First level entry(Page Directory Entry) to a second level small page PTE */
#define ARM_VM_PDE_SHIFT 10
#define ARM_VM_PDE_MASK (~((1 << ARM_VM_PDE_SHIFT) - 1))
/* First level entry(Page Directory Entry) to a 1MB section */
#define ARM_VM_SECTION_SHIFT 20
#define ARM_VM_SECTION_MASK (~((1 << ARM_VM_SECTION_SHIFT) - 1))
#define ARM_VM_DIR_SIZE (ARM_VM_DIR_ENTRIES * ARM_VM_DIR_ENT_SIZE)
#define ARM_PAGEDIR_SIZE (ARM_VM_DIR_SIZE)
#define ARM_VM_PT_SIZE (ARM_VM_PT_ENTRIES * ARM_VM_PT_ENT_SIZE)
#define ARM_PAGETABLE_SIZE (ARM_VM_PT_SIZE)
/* ARM pagefault status bits */
#define ARM_VM_PFE_ALIGN 0x01 /* Pagefault caused by Alignment fault */
#define ARM_VM_PFE_IMAINT 0x04 /* Caused by Instruction cache
maintenance fault */
#define ARM_VM_PFE_TTWALK_L1ABORT 0x0c /* Caused by Synchronous external abort
* on translation table walk (Level 1)
*/
#define ARM_VM_PFE_TTWALK_L2ABORT 0x0e /* Caused by Synchronous external abort
* on translation table walk (Level 2)
*/
#define ARM_VM_PFE_TTWALK_L1PERR 0x1c /* Caused by Parity error
* on translation table walk (Level 1)
*/
#define ARM_VM_PFE_TTWALK_L2PERR 0x1e /* Caused by Parity error
* on translation table walk (Level 2)
*/
#define ARM_VM_PFE_L1TRANS 0x05 /* Caused by Translation fault (Level 1)
*/
#define ARM_VM_PFE_L2TRANS 0x07 /* Caused by Translation fault (Level 2)
*/
#define ARM_VM_PFE_L1ACCESS 0x03 /* Caused by Access flag fault (Level 1)
*/
#define ARM_VM_PFE_L2ACCESS 0x06 /* Caused by Access flag fault (Level 2)
*/
#define ARM_VM_PFE_L1DOMAIN 0x09 /* Caused by Domain fault (Level 1)
*/
#define ARM_VM_PFE_L2DOMAIN 0x0b /* Caused by Domain fault (Level 2)
*/
#define ARM_VM_PFE_L1PERM 0x0d /* Caused by Permission fault (Level 1)
*/
#define ARM_VM_PFE_L2PERM 0x0f /* Caused by Permission fault (Level 2)
*/
#define ARM_VM_PFE_DEBUG 0x02 /* Caused by Debug event */
#define ARM_VM_PFE_ABORT 0x08 /* Caused by Synchronous external abort
*/
#define ARM_VM_PFE_TLB_CONFLICT 0x10 /* Caused by TLB conflict abort
*/
#define ARM_VM_PFE_W (1<<11) /* Caused by write (otherwise read) */
#define ARM_VM_PFE_FS4 (1<<10) /* Fault status (bit 4) */
#define ARM_VM_PFE_FS3_0 0xf /* Fault status (bits 3:0) */
/* Translation table base register specfic flags */
#define ARM_TTBR_C (0x01) /* Cacheable bit. Indicates whether the translation table walk is to Inner Cacheable memory. */
/* RGN bits[4:3] indicates the Outer cacheability attributes
for the memory associated with the translation table walks */
#define ARM_TTBR_OUTER_NC (0x0 << 3) /* Non-cacheable*/
#define ARM_TTBR_OUTER_WBWA (0x1 << 3) /* Outer Write-Back Write-Allocate Cacheable. */
#define ARM_TTBR_OUTER_WT (0x2 << 3) /* Outer Write-Through Cacheable. */
#define ARM_TTBR_OUTER_WBNWA (0x3 << 3) /* Outer Write-Back no Write-Allocate Cacheable. */
#define ARM_TTBR_ADDR_MASK (0xffffc000) /* only the 18 upper bits are to be used as address */
#define ARM_TTBR_FLAGS_CACHED ARM_TTBR_OUTER_WBWA
/* Fault status */
#define ARM_VM_PFE_FS(s) \
((((s) & ARM_VM_PFE_FS4) >> 6) | ((s) & ARM_VM_PFE_FS3_0))
#ifndef __ASSEMBLY__
#include <minix/type.h>
/* structure used by VM to pass data to the kernel while enabling paging */
struct vm_ep_data {
struct mem_map * mem_map;
vir_bytes data_seg_limit;
};
#endif
#endif /* __SYS_VM_ARM_H__ */

View File

@@ -0,0 +1,98 @@
# Makefile for arch-dependent kernel code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
# objects we want unpaged from -lc
MINLIB_OBJS_UNPAGED= get_bp.o
get_bp.o: ${NETBSDSRCDIR}/minix/lib/libc/arch/arm/get_bp.S
# objects we want unpaged from -lsys
SYS_OBJS_UNPAGED=assert.o stacktrace.o
assert.o: ${NETBSDSRCDIR}/minix/lib/libsys/assert.c
stacktrace.o: ${NETBSDSRCDIR}/minix/lib/libsys/stacktrace.c
# objects we want unpaged from -lminc
MINC_OBJS_UNPAGED= atoi.o \
printf.o subr_prf.o \
strcmp.o strcpy.o strlen.o strncmp.o \
memcpy.o memmove.o memset.o \
udivdi3.o umoddi3.o qdivrem.o
MINC_OBJS_UNPAGED+= __aeabi_ldiv0.o __aeabi_idiv0.o __aeabi_uldivmod.o divide.o divsi3.o udivsi3.o
atoi.o: ${NETBSDSRCDIR}/minix/lib/libminc/atoi.c
printf.o: ${NETBSDSRCDIR}/sys/lib/libsa/printf.c
subr_prf.o: ${NETBSDSRCDIR}/sys/lib/libsa/subr_prf.c
memcpy.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memcpy.S
memmove.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memmove.S
memset.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memset.S
strlen.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strlen.S
strcpy.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strcpy.S
strcmp.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strcmp.S
#strcat.o: ${NETBSDSRCDIR}/common/lib/libc/string/strcat.c
__aeabi_idiv0.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/__aeabi_idiv0.c
__aeabi_ldiv0.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/__aeabi_ldiv0.c
__aeabi_uldivmod.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/quad/__aeabi_uldivmod.S
divide.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/divide.S
divsi3.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/divsi3.S
udivsi3.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/udivsi3.S
# the following is required by pre_init.c
strncmp.o: ${NETBSDSRCDIR}/common/lib/libc/string/strncmp.c
# these are required by kprintn.o:
udivdi3.o: ${NETBSDSRCDIR}/common/lib/libc/quad/udivdi3.c
umoddi3.o: ${NETBSDSRCDIR}/common/lib/libc/quad/umoddi3.c
qdivrem.o: ${NETBSDSRCDIR}/common/lib/libc/quad/qdivrem.c
CPPFLAGS.__aeabi_idiv0.c+= -D_STANDALONE
CPPFLAGS.__aeabi_ldiv0.c+= -D_STANDALONE
# LSC: putchar and kputc have the same signature. A bit hackish.
CPPFLAGS.subr_prf.c+= -Dputchar=kputc
# Activate optional support, may be deactivated.
CPPFLAGS.subr_prf.c+= -DLIBSA_PRINTF_LONGLONG_SUPPORT -DLIBSA_PRINTF_WIDTH_SUPPORT
.include "bsp/ti/Makefile.inc"
# some object files we give a symbol prefix (or namespace) of __k_unpaged_
# that must live in their own unique namespace.
#
.for unpaged_obj in head.o pre_init.o direct_tty_utils.o \
pg_utils.o klib.o utility.o arch_reset.o \
${MINLIB_OBJS_UNPAGED} ${MINC_OBJS_UNPAGED} ${SYS_OBJS_UNPAGED} ${BSP_OBJS_UNPAGED}
unpaged_${unpaged_obj}: ${unpaged_obj}
${OBJCOPY} --prefix-symbols=__k_unpaged_ ${.OBJDIR}/${unpaged_obj} $@
UNPAGED_OBJS += unpaged_${unpaged_obj}
ORIG_UNPAGED_OBJS += ${unpaged_obj}
.endfor
CLEANFILES+= ${ORIG_UNPAGED_OBJS}
SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c do_padconf.c \
exception.c hw_intr.c klib.S memory.c \
protect.c direct_tty_utils.c arch_reset.c \
pg_utils.c phys_copy.S phys_memset.S exc.S
OBJS.kernel+= ${UNPAGED_OBJS}
klib.o mpx.o head.o: procoffsets.h
SRCS+= procoffsets.h
PROCOFFSETSCF=procoffsets.cf
.PATH: ${NETBSDSRCDIR}/minix/include/arch/${MACHINE_ARCH}/include
procoffsets.h: ${PROCOFFSETSCF} kernel.h proc.h stackframe.h archtypes.h
${_MKTARGET_CREATE}
${TOOL_CAT} ${HERE}/${PROCOFFSETSCF} | \
${TOOL_GENASSYM} -- ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} >$@.tmp && \
mv -f $@.tmp $@
sconst.h: procoffsets.h
apic_asm.o head.o klib.o mpx.o: sconst.h

View File

@@ -0,0 +1,141 @@
/* ARM-specific clock functions. */
#include "kernel/kernel.h"
#include "kernel/clock.h"
#include "kernel/proc.h"
#include "kernel/interrupt.h"
#include <minix/u64.h>
#include <minix/board.h>
#include "kernel/glo.h"
#include "kernel/profile.h"
#include <assert.h>
#include "kernel/spinlock.h"
#ifdef CONFIG_SMP
#include "kernel/smp.h"
#endif
#include "bsp_timer.h"
#include "bsp_intr.h"
static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
int init_local_timer(unsigned freq)
{
bsp_timer_init(freq);
if (BOARD_IS_BBXM(machine.board_id)) {
tsc_per_ms[0] = 16250;
} else if (BOARD_IS_BB(machine.board_id)) {
tsc_per_ms[0] = 15000;
} else {
panic("Can not do the clock setup. machine (0x%08x) is unknown\n",machine.board_id);
};
return 0;
}
void stop_local_timer(void)
{
bsp_timer_stop();
}
void arch_timer_int_handler(void)
{
bsp_timer_int_handler();
}
void cycles_accounting_init(void)
{
read_tsc_64(get_cpu_var_ptr(cpu, tsc_ctr_switch));
get_cpu_var(cpu, cpu_last_tsc) = 0;
get_cpu_var(cpu, cpu_last_idle) = 0;
}
void context_stop(struct proc * p)
{
u64_t tsc;
u32_t tsc_delta;
u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch);
read_tsc_64(&tsc);
assert(tsc >= *__tsc_ctr_switch);
tsc_delta = tsc - *__tsc_ctr_switch;
p->p_cycles += tsc_delta;
if(kbill_ipc) {
kbill_ipc->p_kipc_cycles += tsc_delta;
kbill_ipc = NULL;
}
if(kbill_kcall) {
kbill_kcall->p_kcall_cycles += tsc_delta;
kbill_kcall = NULL;
}
/*
* deduct the just consumed cpu cycles from the cpu time left for this
* process during its current quantum. Skip IDLE and other pseudo kernel
* tasks
*/
if (p->p_endpoint >= 0) {
#if DEBUG_RACE
p->p_cpu_time_left = 0;
#else
if (tsc_delta < p->p_cpu_time_left) {
p->p_cpu_time_left -= tsc_delta;
} else p->p_cpu_time_left = 0;
#endif
}
*__tsc_ctr_switch = tsc;
}
void context_stop_idle(void)
{
int is_idle;
#ifdef CONFIG_SMP
unsigned cpu = cpuid;
#endif
is_idle = get_cpu_var(cpu, cpu_is_idle);
get_cpu_var(cpu, cpu_is_idle) = 0;
context_stop(get_cpulocal_var_ptr(idle_proc));
if (is_idle)
restart_local_timer();
#if SPROFILE
if (sprofiling)
get_cpulocal_var(idle_interrupted) = 1;
#endif
}
void restart_local_timer(void)
{
}
int register_local_timer_handler(const irq_handler_t handler)
{
return bsp_register_timer_handler(handler);
}
u64_t ms_2_cpu_time(unsigned ms)
{
return (u64_t)(tsc_per_ms[cpuid]) * ms;
}
unsigned cpu_time_2_ms(u64_t cpu_time)
{
return (unsigned long)(cpu_time / tsc_per_ms[cpuid]);
}
short cpu_load(void)
{
return 0;
}

View File

@@ -0,0 +1,56 @@
/* The kernel call implemented in this file:
* m_type: SYS_VMCTL
*
* The parameters for this kernel call are:
* SVMCTL_WHO which process
* SVMCTL_PARAM set this setting (VMCTL_*)
* SVMCTL_VALUE to this value
*/
#include "kernel/system.h"
#include <assert.h>
#include <minix/type.h>
#include "arch_proto.h"
static void set_ttbr(struct proc *p, u32_t ttbr, u32_t *v)
{
/* Set process TTBR. */
p->p_seg.p_ttbr = ttbr;
assert(p->p_seg.p_ttbr);
p->p_seg.p_ttbr_v = v;
if(p == get_cpulocal_var(ptproc)) {
write_ttbr0(p->p_seg.p_ttbr);
}
if(p->p_nr == VM_PROC_NR) {
if (arch_enable_paging(p) != OK)
panic("arch_enable_paging failed");
}
RTS_UNSET(p, RTS_VMINHIBIT);
}
/*===========================================================================*
* arch_do_vmctl *
*===========================================================================*/
int arch_do_vmctl(m_ptr, p)
register message *m_ptr; /* pointer to request message */
struct proc *p;
{
switch(m_ptr->SVMCTL_PARAM) {
case VMCTL_GET_PDBR:
/* Get process page directory base reg (TTBR). */
m_ptr->SVMCTL_VALUE = p->p_seg.p_ttbr;
return OK;
case VMCTL_SETADDRSPACE:
set_ttbr(p, m_ptr->SVMCTL_PTROOT, (u32_t *) m_ptr->SVMCTL_PTROOT_V);
return OK;
case VMCTL_FLUSHTLB:
{
reload_ttbr0();
return OK;
}
}
printf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
return EINVAL;
}

View File

@@ -0,0 +1,82 @@
#include "kernel/kernel.h"
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <machine/cpu.h>
#include <assert.h>
#include <signal.h>
#include <machine/vm.h>
#include <io.h>
#include <minix/board.h>
#include <sys/reboot.h>
#include <minix/u64.h>
#include "archconst.h"
#include "arch_proto.h"
#include "bsp_reset.h"
#include "bsp_serial.h"
#include "kernel/proc.h"
#include "kernel/debug.h"
#include "direct_utils.h"
#include <machine/multiboot.h>
void
halt_cpu(void)
{
asm volatile("dsb");
asm volatile("cpsie i");
asm volatile("wfi");
asm volatile("cpsid i");
}
void
reset(void)
{
bsp_reset(); /* should not exit */
direct_print("Reset not supported.");
while (1);
}
void
poweroff(void)
{
bsp_poweroff();
/* fallback option: hang */
direct_print("Unable to power-off this device.");
while (1);
}
__dead void
arch_shutdown(int how)
{
if((how & RB_POWERDOWN) == RB_POWERDOWN) {
/* Power off if possible, hang otherwise */
poweroff();
NOT_REACHABLE;
}
if(how & RB_HALT) {
/* Hang */
for (; ; ) halt_cpu();
NOT_REACHABLE;
}
/* Reset the system */
reset();
NOT_REACHABLE;
while (1);
}
#ifdef DEBUG_SERIAL
void
ser_putc(char c)
{
bsp_ser_putc(c);
}
#endif

View File

@@ -0,0 +1,218 @@
/* system dependent functions for use inside the whole kernel. */
#include "kernel/kernel.h"
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <minix/cpufeature.h>
#include <assert.h>
#include <signal.h>
#include <machine/vm.h>
#include <machine/signal.h>
#include <arm/armreg.h>
#include <minix/u64.h>
#include "archconst.h"
#include "arch_proto.h"
#include "kernel/proc.h"
#include "kernel/debug.h"
#include "ccnt.h"
#include "bsp_init.h"
#include "bsp_serial.h"
#include "glo.h"
void * k_stacks;
void fpu_init(void)
{
}
void save_local_fpu(struct proc *pr, int retain)
{
}
void save_fpu(struct proc *pr)
{
}
void arch_proc_reset(struct proc *pr)
{
assert(pr->p_nr < NR_PROCS);
/* Clear process state. */
memset(&pr->p_reg, 0, sizeof(pr->p_reg));
if(iskerneln(pr->p_nr)) {
pr->p_reg.psr = INIT_TASK_PSR;
} else {
pr->p_reg.psr = INIT_PSR;
}
}
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state,
int isuser, int trapstyle)
{
assert(sizeof(p->p_reg) == sizeof(*state));
if(state != &p->p_reg) {
memcpy(&p->p_reg, state, sizeof(*state));
}
/* further code is instructed to not touch the context
* any more
*/
p->p_misc_flags |= MF_CONTEXT_SET;
if(!(p->p_rts_flags)) {
printf("WARNINIG: setting full context of runnable process\n");
print_proc(p);
util_stacktrace();
}
}
void arch_set_secondary_ipc_return(struct proc *p, u32_t val)
{
p->p_reg.r1 = val;
}
int restore_fpu(struct proc *pr)
{
return 0;
}
void cpu_identify(void)
{
u32_t midr;
unsigned cpu = cpuid;
asm volatile("mrc p15, 0, %[midr], c0, c0, 0 @ read MIDR\n\t"
: [midr] "=r" (midr));
cpu_info[cpu].implementer = midr >> 24;
cpu_info[cpu].variant = (midr >> 20) & 0xF;
cpu_info[cpu].arch = (midr >> 16) & 0xF;
cpu_info[cpu].part = (midr >> 4) & 0xFFF;
cpu_info[cpu].revision = midr & 0xF;
cpu_info[cpu].freq = 660; /* 660 Mhz hardcoded */
}
void arch_init(void)
{
u32_t value;
k_stacks = (void*) &k_stacks_start;
assert(!((vir_bytes) k_stacks % K_STACK_SIZE));
#ifndef CONFIG_SMP
/*
* use stack 0 and cpu id 0 on a single processor machine, SMP
* configuration does this in smp_init() for all cpus at once
*/
tss_init(0, get_k_stack_top(0));
#endif
/* enable user space access to cycle counter */
/* set cycle counter to 0: ARM ARM B4.1.113 and B4.1.117 */
asm volatile ("MRC p15, 0, %0, c9, c12, 0\t\n": "=r" (value));
value |= PMU_PMCR_C; /* Reset counter */
value |= PMU_PMCR_E; /* Enable counter hardware */
asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n": : "r" (value));
/* enable CCNT counting: ARM ARM B4.1.116 */
value = PMU_PMCNTENSET_C; /* Enable PMCCNTR cycle counter */
asm volatile ("MCR p15, 0, %0, c9, c12, 1\t\n": : "r" (value));
/* enable cycle counter in user mode: ARM ARM B4.1.124 */
value = PMU_PMUSERENR_EN;
asm volatile ("MCR p15, 0, %0, c9, c14, 0\t\n": : "r" (value));
bsp_init();
}
/*===========================================================================*
* do_ser_debug *
*===========================================================================*/
void do_ser_debug()
{
}
void arch_do_syscall(struct proc *proc)
{
/* do_ipc assumes that it's running because of the current process */
assert(proc == get_cpulocal_var(proc_ptr));
/* Make the system call, for real this time. */
proc->p_reg.retreg =
do_ipc(proc->p_reg.retreg, proc->p_reg.r1, proc->p_reg.r2);
}
reg_t svc_stack;
struct proc * arch_finish_switch_to_user(void)
{
char * stk;
struct proc * p;
#ifdef CONFIG_SMP
stk = (char *)tss[cpuid].sp0;
#else
stk = (char *)tss[0].sp0;
#endif
svc_stack = (reg_t)stk;
/* set pointer to the process to run on the stack */
p = get_cpulocal_var(proc_ptr);
*((reg_t *)stk) = (reg_t) p;
/* turn interrupts on */
p->p_reg.psr &= ~(PSR_I|PSR_F);
return p;
}
void fpu_sigcontext(struct proc *pr, struct sigframe_sigcontext *fr, struct sigcontext *sc)
{
}
reg_t arch_get_sp(struct proc *p) { return p->p_reg.sp; }
void get_randomness(struct k_randomness *rand, int source)
{
}
void arch_ser_init(void)
{
bsp_ser_init();
}
/*===========================================================================*/
/* __switch_address_space */
/*===========================================================================*/
/*
* sets the ttbr register to the supplied value if it is not already set to the
* same value in which case it would only result in an extra TLB flush which is
* not desirable
*/
void __switch_address_space(struct proc *p, struct proc **__ptproc)
{
reg_t orig_ttbr, new_ttbr;
new_ttbr = p->p_seg.p_ttbr;
if (new_ttbr == 0)
return;
orig_ttbr = read_ttbr0();
/*
* test if ttbr is loaded with the current value to avoid unnecessary
* TLB flushes
*/
if (new_ttbr == orig_ttbr)
return;
write_ttbr0(new_ttbr);
*__ptproc = p;
return;
}

View File

@@ -0,0 +1,7 @@
#ifndef _BSP_INIT_H_
#define _BSP_INIT_H_
/* BSP init */
void bsp_init();
#endif /* __BSP_INIT_H__ */

View File

@@ -0,0 +1,12 @@
#ifndef _BSP_INTR_H_
#define _BSP_INTR_H_
#ifndef __ASSEMBLY__
void bsp_irq_unmask(int irq);
void bsp_irq_mask(int irq);
void bsp_irq_handle(void);
#endif /* __ASSEMBLY__ */
#endif /* _BSP_INTR_H_ */

View File

@@ -0,0 +1,11 @@
#ifndef _BSP_PADCONF_H_
#define _BSP_PADCONF_H_
#ifndef __ASSEMBLY__
void bsp_padconf_init(void);
int bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value);
#endif /* __ASSEMBLY__ */
#endif /* _BSP_PADCONF_H_ */

View File

@@ -0,0 +1,9 @@
#ifndef _BSP_RESET_H_
#define _BSP_RESET_H_
void bsp_reset_init(void);
void bsp_reset(void);
void bsp_poweroff(void);
void bsp_disable_watchdog(void);
#endif /* _BSP_RESET_H_ */

View File

@@ -0,0 +1,6 @@
#ifndef _BSP_SERIAL_H_
#define _BSP_SERIAL_H_
void bsp_ser_init();
void bsp_ser_putc(char c);
#endif /* _BSP_SERIAL_H_ */

View File

@@ -0,0 +1,13 @@
#ifndef _BSP_TIMER_H_
#define _BSP_TIMER_H_
#ifndef __ASSEMBLY__
void bsp_timer_init(unsigned freq);
void bsp_timer_stop(void);
int bsp_register_timer_handler(const irq_handler_t handler);
void bsp_timer_int_handler(void);
#endif /* __ASSEMBLY__ */
#endif /* _BSP_TIMER_H_ */

View File

@@ -0,0 +1,13 @@
#
# BSP for TI hardware
#
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/bsp/ti
.for unpaged_obj in omap_serial.o omap_rtc.o omap_reset.o
BSP_OBJS_UNPAGED += ${unpaged_obj}
.endfor
SRCS+= omap_init.c omap_serial.c omap_timer.c omap_padconf.c omap_intr.c omap_rtc.c \
omap_reset.c

View File

@@ -0,0 +1,21 @@
#include <sys/types.h>
#include "bsp_init.h"
#include "bsp_padconf.h"
#include "omap_rtc.h"
#include "bsp_reset.h"
void
bsp_init()
{
/* map memory for padconf */
bsp_padconf_init();
/* map memory for rtc */
omap3_rtc_init();
/* map memory for reset control */
bsp_reset_init();
/* disable watchdog */
bsp_disable_watchdog();
}

View File

@@ -0,0 +1,72 @@
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "hw_intr.h"
#include "omap_intr_registers.h"
static struct omap_intr
{
vir_bytes base;
int size;
} omap_intr;
static kern_phys_map intr_phys_map;
int
intr_init(const int auto_eoi)
{
if (BOARD_IS_BBXM(machine.board_id)) {
omap_intr.base = OMAP3_DM37XX_INTR_BASE;
} else if (BOARD_IS_BB(machine.board_id)) {
omap_intr.base = OMAP3_AM335X_INTR_BASE;
} else {
panic
("Can not do the interrupt setup. machine (0x%08x) is unknown\n",
machine.board_id);
};
omap_intr.size = 0x1000; /* 4K */
kern_phys_map_ptr(omap_intr.base, omap_intr.size,
VMMF_UNCACHED | VMMF_WRITE,
&intr_phys_map, (vir_bytes) & omap_intr.base);
return 0;
}
void
bsp_irq_handle(void)
{
/* Function called from assembly to handle interrupts */
/* get irq */
int irq =
mmio_read(omap_intr.base +
OMAP3_INTCPS_SIR_IRQ) & OMAP3_INTR_ACTIVEIRQ_MASK;
/* handle irq */
irq_handle(irq);
/* re-enable. this should not trigger interrupts due to current cpsr
* state */
mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL,
OMAP3_INTR_NEWIRQAGR);
}
void
bsp_irq_unmask(int irq)
{
mmio_write(OMAP3_INTR_MIR_CLEAR(omap_intr.base, irq >> 5),
1 << (irq & 0x1f));
}
void
bsp_irq_mask(const int irq)
{
mmio_write(OMAP3_INTR_MIR_SET(omap_intr.base, irq >> 5),
1 << (irq & 0x1f));
}

View File

@@ -0,0 +1,236 @@
#ifndef _OMAP_INTR_H
#define _OMAP_INTR_H
/* Interrupt controller memory map */
#define OMAP3_DM37XX_INTR_BASE 0x48200000 /* INTCPS physical address */
/* Interrupt controller memory map */
#define OMAP3_AM335X_INTR_BASE 0x48200000 /* INTCPS physical address */
/* Interrupt controller registers */
#define OMAP3_INTCPS_REVISION 0x000 /* IP revision code */
#define OMAP3_INTCPS_SYSCONFIG 0x010 /* Controls params */
#define OMAP3_INTCPS_SYSSTATUS 0x014 /* Status */
#define OMAP3_INTCPS_SIR_IRQ 0x040 /* Active IRQ number */
#define OMAP3_INTCPS_SIR_FIQ 0x044 /* Active FIQ number */
#define OMAP3_INTCPS_CONTROL 0x048 /* New int agreement bits */
#define OMAP3_INTCPS_PROTECTION 0x04C /* Protection for other regs */
#define OMAP3_INTCPS_IDLE 0x050 /* Clock auto-idle/gating */
#define OMAP3_INTCPS_IRQ_PRIORITY 0x060 /* Active IRQ priority level */
#define OMAP3_INTCPS_FIQ_PRIORITY 0x064 /* Active FIQ priority level */
#define OMAP3_INTCPS_THRESHOLD 0x068 /* Priority threshold */
#define OMAP3_INTCPS_ITR0 0x080 /* Raw pre-masking interrupt status */
#define OMAP3_INTCPS_MIR0 0x084 /* Interrupt mask */
#define OMAP3_INTCPS_MIR_CLEAR0 0x088 /* Clear interrupt mask bits */
#define OMAP3_INTCPS_MIR_SET0 0x08C /* Set interrupt mask bits */
#define OMAP3_INTCPS_ISR_SET0 0x090 /* Set software int bits */
#define OMAP3_INTCPS_ISR_CLEAR0 0x094 /* Clear software int bits */
#define OMAP3_INTCPS_PENDING_IRQ0 0x098 /* IRQ status post-masking */
#define OMAP3_INTCPS_PENDING_FIQ0 0x09C /* FIQ status post-masking */
#define OMAP3_INTCPS_ILR0 0x100 /* Priority for interrupts */
#define OMAP3_INTR_ITR(base,n) \
(base + OMAP3_INTCPS_ITR0 + 0x20 * (n))
#define OMAP3_INTR_MIR(base,n) \
(base + OMAP3_INTCPS_MIR0 + 0x20 * (n))
#define OMAP3_INTR_MIR_CLEAR(base,n) \
(base + OMAP3_INTCPS_MIR_CLEAR0 + 0x20 * (n))
#define OMAP3_INTR_MIR_SET(base,n) \
(base + OMAP3_INTCPS_MIR_SET0 + 0x20 * (n))
#define OMAP3_INTR_ISR_SET(base,n) \
(base + OMAP3_INTCPS_ISR_SET0 + 0x20 * (n))
#define OMAP3_INTR_ISR_CLEAR(base,n) \
(base + OMAP3_INTCPS_ISR_CLEAR0 + 0x20 * (n))
#define OMAP3_INTR_PENDING_IRQ(base,n) \
(base + OMAP3_INTCPS_PENDING_IRQ0 + 0x20 * (n))
#define OMAP3_INTR_PENDING_FIQ(base,n) \
(base + OMAP3_INTCPS_PENDING_FIQ0 + 0x20 * (n))
#define OMAP3_INTR_ILR(base,m) \
(base + OMAP3_INTCPS_ILR0 + 0x4 * (m))
#define OMAP3_INTR_ACTIVEIRQ_MASK 0x7f /* Active IRQ mask for SIR_IRQ */
#define OMAP3_INTR_NEWIRQAGR 0x1 /* New IRQ Generation */
#define OMAP3_DM337X_NR_IRQ_VECTORS 96
/* Interrupt mappings */
#define OMAP3_MCBSP2_ST_IRQ 4 /* Sidestone McBSP2 overflow */
#define OMAP3_MCBSP3_ST_IRQ 5 /* Sidestone McBSP3 overflow */
#define OMAP3_SYS_NIRQ 7 /* External source (active low) */
#define OMAP3_SMX_DBG_IRQ 9 /* L3 interconnect error for debug */
#define OMAP3_SMX_APP_IRQ 10 /* L3 interconnect error for application */
#define OMAP3_PRCM_IRQ 11 /* PRCM module */
#define OMAP3_SDMA0_IRQ 12 /* System DMA request 0 */
#define OMAP3_SDMA1_IRQ 13 /* System DMA request 1 */
#define OMAP3_SDMA2_IRQ 14 /* System DMA request 2 */
#define OMAP3_SDMA3_IRQ 15 /* System DMA request 3 */
#define OMAP3_MCBSP1_IRQ 16 /* McBSP module 1 */
#define OMAP3_MCBSP2_IRQ 17 /* McBSP module 2 */
#define OMAP3_GPMC_IRQ 20 /* General-purpose memory controller */
#define OMAP3_SGX_IRQ 21 /* 2D/3D graphics module */
#define OMAP3_MCBSP3_IRQ 22 /* McBSP module 3 */
#define OMAP3_MCBSP4_IRQ 23 /* McBSP module 4 */
#define OMAP3_CAM0_IRQ 24 /* Camera interface request 0 */
#define OMAP3_DSS_IRQ 25 /* Display subsystem module */
#define OMAP3_MAIL_U0_IRQ 26 /* Mailbox user 0 request */
#define OMAP3_MCBSP5_IRQ 27 /* McBSP module 5 */
#define OMAP3_IVA2_MMU_IRQ 28 /* IVA2 MMU */
#define OMAP3_GPIO1_IRQ 29 /* GPIO module 1 */
#define OMAP3_GPIO2_IRQ 30 /* GPIO module 2 */
#define OMAP3_GPIO3_IRQ 31 /* GPIO module 3 */
#define OMAP3_GPIO4_IRQ 32 /* GPIO module 4 */
#define OMAP3_GPIO5_IRQ 33 /* GPIO module 5 */
#define OMAP3_GPIO6_IRQ 34 /* GPIO module 6 */
#define OMAP3_WDT3_IRQ 36 /* Watchdog timer module 3 overflow */
#define OMAP3_GPT1_IRQ 37 /* General-purpose timer module 1 */
#define OMAP3_GPT2_IRQ 38 /* General-purpose timer module 2 */
#define OMAP3_GPT3_IRQ 39 /* General-purpose timer module 3 */
#define OMAP3_GPT4_IRQ 40 /* General-purpose timer module 4 */
#define OMAP3_GPT5_IRQ 41 /* General-purpose timer module 5 */
#define OMAP3_GPT6_IRQ 42 /* General-purpose timer module 6 */
#define OMAP3_GPT7_IRQ 43 /* General-purpose timer module 7 */
#define OMAP3_GPT8_IRQ 44 /* General-purpose timer module 8 */
#define OMAP3_GPT9_IRQ 45 /* General-purpose timer module 9 */
#define OMAP3_GPT10_IRQ 46 /* General-purpose timer module 10 */
#define OMAP3_GPT11_IRQ 47 /* General-purpose timer module 11 */
#define OMAP3_SPI4_IRQ 48 /* McSPI module 4 */
#define OMAP3_MCBSP4_TX_IRQ 54 /* McBSP module 4 transmit */
#define OMAP3_MCBSP4_RX_IRQ 55 /* McBSP module 4 receive */
#define OMAP3_I2C1_IRQ 56 /* I2C module 1 */
#define OMAP3_I2C2_IRQ 57 /* I2C module 2 */
#define OMAP3_HDQ_IRQ 58 /* HDQ/1-Wire */
#define OMAP3_MCBSP1_TX_IRQ 59 /* McBSP module 1 transmit */
#define OMAP3_MCBSP1_RX_IRQ 60 /* McBSP module 1 receive */
#define OMAP3_I2C3_IRQ 61 /* I2C module 3 */
#define OMAP3_MCBSP2_TX_IRQ 62 /* McBSP module 2 transmit */
#define OMAP3_MCBSP2_RX_IRQ 63 /* McBSP module 2 receive */
#define OMAP3_SPI1_IRQ 65 /* McSPI module 1 */
#define OMAP3_SPI2_IRQ 66 /* McSPI module 2 */
#define OMAP3_UART1_IRQ 72 /* UART module 1 */
#define OMAP3_UART2_IRQ 73 /* UART module 2 */
#define OMAP3_PBIAS_IRQ 75 /* Merged interrupt for PBIASlite 1/2 */
#define OMAP3_OHCI_IRQ 76 /* OHCI HSUSB MP Host Interrupt */
#define OMAP3_EHCI_IRQ 77 /* EHCI HSUSB MP Host Interrupt */
#define OMAP3_TLL_IRQ 78 /* HSUSB MP TLL Interrupt */
#define OMAP3_MCBSP5_TX_IRQ 81 /* McBSP module 5 transmit */
#define OMAP3_MCBSP5_RX_IRQ 82 /* McBSP module 5 receive */
#define OMAP3_MMC1_IRQ 83 /* MMC/SD module 1 */
#define OMAP3_MMC2_IRQ 86 /* MMC/SD module 2 */
#define OMAP3_ICR_IRQ 87 /* MPU ICR */
#define OMAP3_D2DFRINT_IRQ 88 /* 3G coproc (in stacked modem config) */
#define OMAP3_MCBSP3_TX_IRQ 89 /* McBSP module 3 transmit */
#define OMAP3_MCBSP3_RX_IRQ 90 /* McBSP module 3 receive */
#define OMAP3_SPI3_IRQ 91 /* McSPI module 3 */
#define OMAP3_HSUSB_MC_IRQ 92 /* High-speed USB OTG */
#define OMAP3_HSUSB_DMA_IRQ 93 /* High-speed USB OTG DMA */
#define OMAP3_MMC3_IRQ 94 /* MMC/SD module 3 */
#define AM335X_INT_EMUINT 0 /* Emulation interrupt (EMUICINTR) */
#define AM335X_INT_COMMTX 1 /* CortexA8 COMMTX */
#define AM335X_INT_COMMRX 2 /* CortexA8 COMMRX */
#define AM335X_INT_BENCH 3 /* CortexA8 NPMUIRQ */
#define AM335X_INT_ELM_IRQ 4 /* Sinterrupt (Error location process completion) */
#define AM335X_INT_NMI 7 /* nmi_int */
#define AM335X_INT_L3DEBUG 9 /* l3_FlagMux_top_FlagOut1 */
#define AM335X_INT_L3APPINT 10 /* l3_FlagMux_top_FlagOut0 */
#define AM335X_INT_PRCMINT 11 /* irq_mpu */
#define AM335X_INT_EDMACOMPINT 12 /* tpcc_int_pend_po0 */
#define AM335X_INT_EDMAMPERR 13 /* tpcc_mpint_pend_po */
#define AM335X_INT_EDMAERRINT 14 /* tpcc_errint_pend_po */
#define AM335X_INT_ADC_TSC_GENINT 16 /* gen_intr_pend */
#define AM335X_INT_USBSSINT 17 /* usbss_intr_pend */
#define AM335X_INT_USB0 18 /* usb0_intr_pend */
#define AM335X_INT_USB1 19 /* usb1_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT0 20 /* pr1_host_intr0_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT1 21 /* pr1_host_intr1_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT2 22 /* pr1_host_intr2_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT3 23 /* pr1_host_intr3_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT4 24 /* pr1_host_intr4_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT5 25 /* pr1_host_intr5_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT6 26 /* pr1_host_intr6_intr_pend */
#define AM335X_INT_PRUSS1_EVTOUT7 27 /* pr1_host_intr7_intr_pend */
#define AM335X_INT_MMCSD1INT 28 /* MMCSD1 SINTERRUPTN */
#define AM335X_INT_MMCSD2INT 29 /* MMCSD2 SINTERRUPT */
#define AM335X_INT_I2C2INT 30 /* I2C2 POINTRPEND */
#define AM335X_INT_eCAP0INT 31 /* ecap_intr_intr_pend */
#define AM335X_INT_GPIOINT2A 32 /* GPIO 2 POINTRPEND1 */
#define AM335X_INT_GPIOINT2B 33 /* GPIO 2 POINTRPEND2 */
#define AM335X_INT_USBWAKEUP 34 /* USBSS slv0p_Swakeup */
#define AM335X_INT_LCDCINT 36 /* LCDC lcd_irq */
#define AM335X_INT_GFXINT 37 /* SGX530 THALIAIRQ */
#define AM335X_INT_ePWM2INT 39 /* (PWM Subsystem) epwm_intr_intr_pend */
#define AM335X_INT_3PGSWRXTHR0 40 /* (Ethernet) c0_rx_thresh_pend (RX_THRESH_PULSE) */
#define AM335X_INT_3PGSWRXINT0 41 /* CPSW (Ethernet) c0_rx_pend */
#define AM335X_INT_3PGSWTXINT0 42 /* CPSW (Ethernet) c0_tx_pend */
#define AM335X_INT_3PGSWMISC0 43 /* CPSW (Ethernet) c0_misc_pend */
#define AM335X_INT_UART3INT 44 /* UART3 niq */
#define AM335X_INT_UART4INT 45 /* UART4 niq */
#define AM335X_INT_UART5INT 46 /* UART5 niq */
#define AM335X_INT_eCAP1INT 47 /* (PWM Subsystem) ecap_intr_intr_pend */
#define AM335X_INT_DCAN0_INT0 52 /* DCAN0 dcan_intr0_intr_pend */
#define AM335X_INT_DCAN0_INT1 53 /* DCAN0 dcan_intr1_intr_pend */
#define AM335X_INT_DCAN0_PARITY 54 /* DCAN0 dcan_uerr_intr_pend */
#define AM335X_INT_DCAN1_INT0 55 /* DCAN1 dcan_intr0_intr_pend */
#define AM335X_INT_DCAN1_INT1 56 /* DCAN1 dcan_intr1_intr_pend */
#define AM335X_INT_DCAN1_PARITY 57 /* DCAN1 dcan_uerr_intr_pend */
#define AM335X_INT_ePWM0_TZINT 58 /* eHRPWM0 TZ interrupt (PWM epwm_tz_intr_pend Subsystem) */
#define AM335X_INT_ePWM1_TZINT 59 /* eHRPWM1 TZ interrupt (PWM epwm_tz_intr_pend Subsystem) */
#define AM335X_INT_ePWM2_TZINT 60 /* eHRPWM2 TZ interrupt (PWM epwm_tz_intr_pend Subsystem) */
#define AM335X_INT_eCAP2INT 61 /* eCAP2 (PWM Subsystem) ecap_intr_intr_pend */
#define AM335X_INT_GPIOINT3A 62 /* GPIO 3 POINTRPEND1 */
#define AM335X_INT_GPIOINT3B 63 /* GPIO 3 POINTRPEND2 */
#define AM335X_INT_MMCSD0INT 64 /* MMCSD0 SINTERRUPTN */
#define AM335X_INT_SPI0INT 65 /* McSPI0 SINTERRUPTN */
#define AM335X_INT_TINT0 66 /* Timer0 POINTR_PEND */
#define AM335X_INT_TINT1_1MS 67 /* DMTIMER_1ms POINTR_PEND */
#define AM335X_INT_TINT2 68 /* DMTIMER2 POINTR_PEND */
#define AM335X_INT_TINT3 69 /* DMTIMER3 POINTR_PEND */
#define AM335X_INT_I2C0INT 70 /* I2C0 POINTRPEND */
#define AM335X_INT_I2C1INT 71 /* I2C1 POINTRPEND */
#define AM335X_INT_UART0INT 72 /* UART0 niq */
#define AM335X_INT_UART1INT 73 /* UART1 niq */
#define AM335X_INT_UART2INT 74 /* UART2 niq */
#define AM335X_INT_RTCINT 75 /* RTC timer_intr_pend */
#define AM335X_INT_RTCALARMINT 76 /* RTC alarm_intr_pend */
#define AM335X_INT_MBINT0 77 /* Mailbox0 (mail_u0_irq) initiator_sinterrupt_q_n */
#define AM335X_INT_M3_TXEV 78 /* Wake M3 Subsystem TXEV */
#define AM335X_INT_eQEP0INT 79 /* eQEP0 (PWM Subsystem) eqep_intr_intr_pend */
#define AM335X_INT_MCATXINT0 80 /* McASP0 mcasp_x_intr_pend */
#define AM335X_INT_MCARXINT0 81 /* McASP0 mcasp_r_intr_pend */
#define AM335X_INT_MCATXINT1 82 /* McASP1 mcasp_x_intr_pend */
#define AM335X_INT_MCARXINT1 83 /* McASP1 mcasp_r_intr_pend */
#define AM335X_INT_ePWM0INT 86 /* (PWM Subsystem) epwm_intr_intr_pend */
#define AM335X_INT_ePWM1INT 87 /* (PWM Subsystem) epwm_intr_intr_pend */
#define AM335X_INT_eQEP1INT 88 /* (PWM Subsystem) eqep_intr_intr_pend */
#define AM335X_INT_eQEP2INT 89 /* (PWM Subsystem) eqep_intr_intr_pend */
#define AM335X_INT_DMA_INTR_PIN2 90 /* External DMA/Interrupt Pin2 pi_x_dma_event_intr2 (xdma_event_intr2) */
#define AM335X_INT_WDT1INT 91 /* (Public Watchdog) WDTIMER1 PO_INT_PEND */
#define AM335X_INT_TINT4 92 /* DMTIMER4 POINTR_PEN */
#define AM335X_INT_TINT5 93 /* DMTIMER5 POINTR_PEN */
#define AM335X_INT_TINT6 94 /* DMTIMER6 POINTR_PEND */
#define AM335X_INT_TINT7 95 /* DMTIMER7 POINTR_PEND */
#define AM335X_INT_GPIOINT0A 96 /* GPIO 0 POINTRPEND1 */
#define AM335X_INT_GPIOINT0B 97 /* GPIO 0 POINTRPEND2 */
#define AM335X_INT_GPIOINT1A 98 /* GPIO 1 POINTRPEND1 */
#define AM335X_INT_GPIOINT1B 99 /* GPIO 1 POINTRPEND2 */
#define AM335X_INT_GPMCINT 100 /* GPMC gpmc_sinterrupt */
#define AM335X_INT_DDRERR0 101 /* EMIF sys_err_intr_pend */
#define AM335X_INT_TCERRINT0 112 /* TPTC0 tptc_erint_pend_po */
#define AM335X_INT_TCERRINT1 113 /* TPTC1 tptc_erint_pend_po */
#define AM335X_INT_TCERRINT2 114 /* TPTC2 tptc_erint_pend_po */
#define AM335X_INT_ADC_TSC_PENINT 115 /* ADC_TSC pen_intr_pend */
#define AM335X_INT_SMRFLX_Sabertooth 120 /* Smart Reflex 0 intrpen */
#define AM335X_INT_SMRFLX_Core 121 /* Smart Reflex 1 intrpend */
#define AM335X_INT_DMA_INTR_PIN0 123 /* pi_x_dma_event_intr0 (xdma_event_intr0) */
#define AM335X_INT_DMA_INTR_PIN1 124 /* pi_x_dma_event_intr1 (xdma_event_intr1) */
#define AM335X_INT_SPI1INT 125 /* McSPI1 SINTERRUPTN */
#define OMAP3_AM335X_NR_IRQ_VECTORS 125
#endif /* _OMAP_INTR_H */

View File

@@ -0,0 +1,83 @@
/* Implements sys_padconf() for the AM335X and DM37XX. */
#include "kernel/kernel.h"
#include "arch_proto.h"
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/mmio.h>
#include <minix/padconf.h>
#include <minix/board.h>
#include <minix/com.h>
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "bsp_padconf.h"
struct omap_padconf
{
vir_bytes base;
vir_bytes offset;
vir_bytes size;
unsigned int board_filter_value;
unsigned int board_filter_mask;
};
static struct omap_padconf omap_padconfs[] = {
{
.base = PADCONF_DM37XX_REGISTERS_BASE,
.offset = PADCONF_DM37XX_REGISTERS_OFFSET,
.size = PADCONF_DM37XX_REGISTERS_SIZE,
.board_filter_value = BOARD_FILTER_BBXM_VALUE,
.board_filter_mask = BOARD_FILTER_BBXM_MASK,
},
{
.base = PADCONF_AM335X_REGISTERS_BASE,
.offset = PADCONF_AM335X_REGISTERS_OFFSET,
.size = PADCONF_AM335X_REGISTERS_SIZE,
.board_filter_value = BOARD_FILTER_BB_VALUE,
.board_filter_mask = BOARD_FILTER_BB_MASK,
},
};
/* initialized in init */
static struct omap_padconf *omap_padconf;
static kern_phys_map padconf_phys_map;
int
bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value)
{
/* check that the value will be inside the padconf memory range */
if (padconf >= (omap_padconf->size - omap_padconf->offset)) {
return EINVAL; /* outside of valid range */
}
set32(padconf + omap_padconf->base + omap_padconf->offset, mask,
value);
return OK;
}
void
bsp_padconf_init(void)
{
int x;
omap_padconf = NULL;
/* find the correct padconf */
for (x = 0; x < sizeof(omap_padconfs) / sizeof(omap_padconfs[0]); x++) {
if ((omap_padconfs[x].board_filter_mask & machine.board_id) ==
omap_padconfs[x].board_filter_value) {
omap_padconf = &omap_padconfs[x];
break;
}
}
assert(omap_padconf);
kern_phys_map_ptr(omap_padconf->base, omap_padconf->size,
VMMF_UNCACHED | VMMF_WRITE,
&padconf_phys_map, (vir_bytes) & omap_padconf->base);
return;
}

View File

@@ -0,0 +1,100 @@
#include <assert.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "bsp_reset.h"
#include "omap_timer_registers.h"
#include "omap_rtc.h"
#define AM335X_CM_BASE 0x44E00000
#define AM335X_CM_SIZE 0x1000
#define AM335X_PRM_DEVICE_OFFSET 0xf00
#define AM335X_PRM_RSTCTRL_REG 0x00
#define AM335X_RST_GLOBAL_WARM_SW_BIT 0
#define DM37XX_CM_BASE 0x48307000
#define DM37XX_CM_SIZE 0x1000
#define DM37XX_PRM_RSTCTRL_REG 0x250
#define DM37XX_RST_DPLL3_BIT 2
struct omap_reset
{
vir_bytes base;
vir_bytes size;
};
static struct omap_reset omap_reset;
static kern_phys_map reset_phys_map;
void
bsp_reset_init(void)
{
if (BOARD_IS_BBXM(machine.board_id)) {
omap_reset.base = DM37XX_CM_BASE;
omap_reset.size = DM37XX_CM_SIZE;
} else if (BOARD_IS_BB(machine.board_id)) {
omap_reset.base = AM335X_CM_BASE;
omap_reset.size = AM335X_CM_SIZE;
}
kern_phys_map_ptr(omap_reset.base, omap_reset.size,
VMMF_UNCACHED | VMMF_WRITE,
&reset_phys_map, (vir_bytes) & omap_reset.base);
}
void
bsp_reset(void)
{
if (BOARD_IS_BBXM(machine.board_id)) {
mmio_set((omap_reset.base + DM37XX_PRM_RSTCTRL_REG),
(1 << DM37XX_RST_DPLL3_BIT));
} else if (BOARD_IS_BB(machine.board_id)) {
mmio_set((omap_reset.base + AM335X_PRM_DEVICE_OFFSET +
AM335X_PRM_RSTCTRL_REG),
(1 << AM335X_RST_GLOBAL_WARM_SW_BIT));
}
}
void
bsp_poweroff(void)
{
/*
* The am335x can signal an external power management chip to cut the power
* by toggling the PMIC_POWER_EN pin. It might fail if there isn't an
* external PMIC or if the PMIC hasn't been configured to respond to toggles.
* The only way to pull the pin low is via ALARM2 (see TRM 20.3.3.8).
* At this point PM should have already signaled readclock to set the alarm.
*/
if (BOARD_IS_BB(machine.board_id)) {
/* rtc was frozen to prevent premature power-off, unfreeze it
* now */
omap3_rtc_run();
/* wait for the alarm to go off and PMIC to disable power to
* SoC */
while (1);
}
}
void bsp_disable_watchdog(void)
{
if(BOARD_IS_BB(machine.board_id)) {
mmio_write(AM335X_WDT_BASE+AM335X_WDT_WSPR, 0xAAAA);
while(mmio_read(AM335X_WDT_BASE+AM335X_WDT_WWPS) != 0) ;
mmio_write(AM335X_WDT_BASE+AM335X_WDT_WSPR, 0x5555);
while(mmio_read(AM335X_WDT_BASE+AM335X_WDT_WWPS) != 0) ;
}
}

View File

@@ -0,0 +1,58 @@
/*
* This is a mini driver for the AM335X Real Time Clock. The majority of the
* work is done in user space in readclock, but for power-off the clock needs
* to be put into run mode at the last possible moment in arch_reset.c. This
* driver just implements mapping the memory and re-starting the clock.
*/
#include <assert.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "omap_rtc.h"
#define RTC_SS_BASE 0x44e3e000
#define RTC_SS_SIZE 0x1000
#define RTC_CTRL_REG 0x40
#define RTC_CTRL_RTC_STOP_BIT 0
struct omap_rtc
{
vir_bytes base;
vir_bytes size;
};
static struct omap_rtc omap_rtc = {
.base = RTC_SS_BASE,
.size = RTC_SS_SIZE
};
static kern_phys_map rtc_phys_map;
void
omap3_rtc_init(void)
{
if (BOARD_IS_BB(machine.board_id)) {
kern_phys_map_ptr(omap_rtc.base, omap_rtc.size,
VMMF_UNCACHED | VMMF_WRITE, &rtc_phys_map,
(vir_bytes) & omap_rtc.base);
}
}
void
omap3_rtc_run(void)
{
if (BOARD_IS_BB(machine.board_id)) {
/* Setting the stop bit starts the RTC running */
mmio_set((omap_rtc.base + RTC_CTRL_REG),
(1 << RTC_CTRL_RTC_STOP_BIT));
}
}

View File

@@ -0,0 +1,7 @@
#ifndef __OMAP_RTC_H
#define __OMAP_RTC_H
void omap3_rtc_init(void);
void omap3_rtc_run(void);
#endif /* __OMAP_RTC_H */

View File

@@ -0,0 +1,84 @@
#include <assert.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "omap_serial.h"
struct omap_serial
{
vir_bytes base;
vir_bytes size;
};
static struct omap_serial omap_serial = {
.base = 0,
};
static kern_phys_map serial_phys_map;
/*
* In kernel serial for the omap. The serial driver like most other
* drivers needs to be started early and even before the MMU is turned on.
* We start by directly accessing the hardware memory address. Later on
* a when the MMU is turned on we still use a 1:1 mapping for these addresses.
*
* Pretty soon we are going to remap these addresses at later stage. And this
* requires us to use a dynamic base address. The idea is to receive a callback
* from VM with the new address to use.
*
* We also anticipate on the beaglebone port an try to keep the differences between
* the drivers to a minimum by initializing a struct here and not using (to much)
* constants in the code.
*
* The serial driver also gets used in the "pre_init" stage before the kernel is loaded
* in high memory so keep in mind there are two copies of this code in the kernel.
*/
void
bsp_ser_init()
{
if (BOARD_IS_BBXM(machine.board_id)) {
omap_serial.base = OMAP3_DM37XX_DEBUG_UART_BASE;
} else if (BOARD_IS_BB(machine.board_id)) {
omap_serial.base = OMAP3_AM335X_DEBUG_UART_BASE;
}
omap_serial.size = 0x1000; /* 4k */
kern_phys_map_ptr(omap_serial.base, omap_serial.size,
VMMF_UNCACHED | VMMF_WRITE, &serial_phys_map,
(vir_bytes) & omap_serial.base);
assert(omap_serial.base);
}
void
bsp_ser_putc(char c)
{
int i;
assert(omap_serial.base);
/* Wait until FIFO's empty */
for (i = 0; i < 100000; i++) {
if (mmio_read(omap_serial.base + OMAP3_LSR) & OMAP3_LSR_THRE) {
break;
}
}
/* Write character */
mmio_write(omap_serial.base + OMAP3_THR, c);
/* And wait again until FIFO's empty to prevent TTY from overwriting */
for (i = 0; i < 100000; i++) {
if (mmio_read(omap_serial.base +
OMAP3_LSR) & (OMAP3_LSR_THRE | OMAP3_LSR_TEMT)) {
break;
}
}
}

View File

@@ -0,0 +1,27 @@
#ifndef _OMAP_SERIAL_H
#define _OMAP_SERIAL_H
/* UART register map */
#define OMAP3_DM37XX_DEBUG_UART_BASE 0x49020000 /* UART3 physical address */
#define OMAP3_AM335X_DEBUG_UART_BASE 0x44E09000 /* UART0? physical address */
/* UART registers */
#define OMAP3_THR 0x000 /* Transmit holding register */
#define OMAP3_LSR 0x014 /* Line status register */
#define OMAP3_SSR 0x044 /* Supplementary status register */
/* Line status register fields */
#define OMAP3_LSR_TEMT 0x40 /* Transmitter empty */
#define OMAP3_LSR_THRE 0x20 /* Transmit-hold-register empty */
/* Supplementary status register fields */
#define OMAP3_SSR_TX_FIFO_FULL (1 << 0) /* Transmit FIFO full */
#ifndef __ASSEMBLY__
void omap3_ser_init();
void omap3_ser_putc(char c);
#endif /* __ASSEMBLY__ */
#endif /* _OMAP_SERIAL_H */

View File

@@ -0,0 +1,397 @@
#include "kernel/kernel.h"
#include "kernel/clock.h"
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/board.h>
#include <minix/mmio.h>
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "arch_proto.h"
#include "bsp_timer.h"
#include "omap_timer_registers.h"
#include "omap_intr_registers.h"
#include "bsp_intr.h"
/* interrupt handler hook */
static irq_hook_t omap3_timer_hook;
static u64_t high_frc;
struct omap_timer_registers;
struct omap_timer
{
vir_bytes base;
int irq_nr;
struct omap_timer_registers *regs;
};
struct omap_timer_registers
{
vir_bytes TIDR;
vir_bytes TIOCP_CFG;
vir_bytes TISTAT;
vir_bytes TISR;
vir_bytes TIER;
vir_bytes TWER;
vir_bytes TCLR;
vir_bytes TCRR;
vir_bytes TLDR;
vir_bytes TTGR;
vir_bytes TWPS;
vir_bytes TMAR;
vir_bytes TCAR1;
vir_bytes TSICR;
vir_bytes TCAR2;
vir_bytes TPIR;
vir_bytes TNIR;
vir_bytes TCVR;
vir_bytes TOCR;
vir_bytes TOWR;
};
static struct omap_timer_registers regs_v1 = {
.TIDR = OMAP3_TIMER_TIDR,
.TIOCP_CFG = OMAP3_TIMER_TIOCP_CFG,
.TISTAT = OMAP3_TIMER_TISTAT,
.TISR = OMAP3_TIMER_TISR,
.TIER = OMAP3_TIMER_TIER,
.TWER = OMAP3_TIMER_TWER,
.TCLR = OMAP3_TIMER_TCLR,
.TCRR = OMAP3_TIMER_TCRR,
.TLDR = OMAP3_TIMER_TLDR,
.TTGR = OMAP3_TIMER_TTGR,
.TWPS = OMAP3_TIMER_TWPS,
.TMAR = OMAP3_TIMER_TMAR,
.TCAR1 = OMAP3_TIMER_TCAR1,
.TSICR = OMAP3_TIMER_TSICR,
.TCAR2 = OMAP3_TIMER_TCAR2,
.TPIR = OMAP3_TIMER_TPIR,
.TNIR = OMAP3_TIMER_TNIR,
.TCVR = OMAP3_TIMER_TCVR,
.TOCR = OMAP3_TIMER_TOCR,
.TOWR = OMAP3_TIMER_TOWR,
};
/* AM335X has a different ip block for the non
1ms timers */
static struct omap_timer_registers regs_v2 = {
.TIDR = AM335X_TIMER_TIDR,
.TIOCP_CFG = AM335X_TIMER_TIOCP_CFG,
.TISTAT = AM335X_TIMER_IRQSTATUS_RAW,
.TISR = AM335X_TIMER_IRQSTATUS,
.TIER = AM335X_TIMER_IRQENABLE_SET,
.TWER = AM335X_TIMER_IRQWAKEEN,
.TCLR = AM335X_TIMER_TCLR,
.TCRR = AM335X_TIMER_TCRR,
.TLDR = AM335X_TIMER_TLDR,
.TTGR = AM335X_TIMER_TTGR,
.TWPS = AM335X_TIMER_TWPS,
.TMAR = AM335X_TIMER_TMAR,
.TCAR1 = AM335X_TIMER_TCAR1,
.TSICR = AM335X_TIMER_TSICR,
.TCAR2 = AM335X_TIMER_TCAR2,
.TPIR = -1, /* UNDEF */
.TNIR = -1, /* UNDEF */
.TCVR = -1, /* UNDEF */
.TOCR = -1, /* UNDEF */
.TOWR = -1 /* UNDEF */
};
static struct omap_timer dm37xx_timer = {
.base = OMAP3_GPTIMER1_BASE,
.irq_nr = OMAP3_GPT1_IRQ,
.regs = &regs_v1
};
/* free running timer */
static struct omap_timer dm37xx_fr_timer = {
.base = OMAP3_GPTIMER10_BASE,
.irq_nr = OMAP3_GPT10_IRQ,
.regs = &regs_v1
};
/* normal timer */
static struct omap_timer am335x_timer = {
.base = AM335X_DMTIMER1_1MS_BASE,
.irq_nr = AM335X_INT_TINT1_1MS,
.regs = &regs_v1
};
/* free running timer */
static struct omap_timer am335x_fr_timer = {
.base = AM335X_DMTIMER7_BASE,
.irq_nr = AM335X_INT_TINT7,
.regs = &regs_v2
};
static struct omap_timer *timer;
static struct omap_timer *fr_timer;
static int done = 0;
int
bsp_register_timer_handler(const irq_handler_t handler)
{
/* Initialize the CLOCK's interrupt hook. */
omap3_timer_hook.proc_nr_e = NONE;
omap3_timer_hook.irq = timer->irq_nr;
put_irq_handler(&omap3_timer_hook, timer->irq_nr, handler);
/* only unmask interrupts after registering */
bsp_irq_unmask(timer->irq_nr);
return 0;
}
/* meta data for remapping */
static kern_phys_map timer_phys_map;
static kern_phys_map fr_timer_phys_map;
static kern_phys_map fr_timer_user_phys_map; /* struct for when the free */
/* running timer is mapped to */
/* userland */
/* callback for when the free running clock gets mapped */
int
kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address)
{
/* the only thing we need to do at this stage is to set the address */
/* in the kerninfo struct */
if (BOARD_IS_BBXM(machine.board_id)) {
minix_kerninfo.minix_frclock_tcrr = address + OMAP3_TIMER_TCRR;
minix_kerninfo.minix_arm_frclock_hz = 1625000;
} else if (BOARD_IS_BB(machine.board_id)) {
minix_kerninfo.minix_frclock_tcrr =
address + AM335X_TIMER_TCRR;
minix_kerninfo.minix_arm_frclock_hz = 1500000;
}
return 0;
}
void
omap3_frclock_init(void)
{
u32_t tisr;
/* enable the clock */
if (BOARD_IS_BBXM(machine.board_id)) {
fr_timer = &dm37xx_fr_timer;
kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_WRITE, &fr_timer_phys_map,
(vir_bytes) & fr_timer->base);
/* the timer is also mapped in user space hence the this */
/* second mapping and callback to set kerninfo frclock_tcrr */
kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_USER,
&fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
/* Stop timer */
mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
OMAP3_TCLR_ST);
/* Use functional clock source for GPTIMER10 */
mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10);
/* Scale timer down to 13/8 = 1.625 Mhz to roughly get
* microsecond ticks */
/* The scale is computed as 2^(PTV+1). So if PTV == 2, we get
* 2^3 = 8. */
mmio_set(fr_timer->base + fr_timer->regs->TCLR,
(2 << OMAP3_TCLR_PTV));
} else if (BOARD_IS_BB(machine.board_id)) {
fr_timer = &am335x_fr_timer;
kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_WRITE,
&fr_timer_phys_map, (vir_bytes) & fr_timer->base);
/* the timer is also mapped in user space hence the this */
/* second mapping and callback to set kerninfo frclock_tcrr */
kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_USER,
&fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
/* Disable the module and wait for the module to be disabled */
set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
CM_MODULEMODE_DISABLED);
while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
!= CM_CLKCTRL_IDLEST_DISABLE);
set32(CLKSEL_TIMER7_CLK, CLKSEL_TIMER7_CLK_SEL_MASK,
CLKSEL_TIMER7_CLK_SEL_SEL2);
while ((read32(CLKSEL_TIMER7_CLK) & CLKSEL_TIMER7_CLK_SEL_MASK)
!= CLKSEL_TIMER7_CLK_SEL_SEL2);
/* enable the module and wait for the module to be ready */
set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
CM_MODULEMODE_ENABLE);
while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
!= CM_CLKCTRL_IDLEST_FUNC);
/* Stop timer */
mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
OMAP3_TCLR_ST);
/* 24Mhz / 16 = 1.5 Mhz */
mmio_set(fr_timer->base + fr_timer->regs->TCLR,
(3 << OMAP3_TCLR_PTV));
}
/* Start and auto-reload at 0 */
mmio_write(fr_timer->base + fr_timer->regs->TLDR, 0x0);
mmio_write(fr_timer->base + fr_timer->regs->TCRR, 0x0);
/* Set up overflow interrupt */
tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
OMAP3_TISR_TCAR_IT_FLAG;
/* Clear interrupt status */
mmio_write(fr_timer->base + fr_timer->regs->TISR, tisr);
mmio_write(fr_timer->base + fr_timer->regs->TIER,
OMAP3_TIER_OVF_IT_ENA);
/* Start timer */
mmio_set(fr_timer->base + fr_timer->regs->TCLR,
OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST |
OMAP3_TCLR_PRE);
done = 1;
}
void
omap3_frclock_stop()
{
mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST);
}
void
bsp_timer_init(unsigned freq)
{
/* we only support 1ms resolution */
u32_t tisr;
if (BOARD_IS_BBXM(machine.board_id)) {
timer = &dm37xx_timer;
kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_WRITE,
&timer_phys_map, (vir_bytes) & timer->base);
/* Stop timer */
mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
/* Use 32 KHz clock source for GPTIMER1 */
mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1);
} else if (BOARD_IS_BB(machine.board_id)) {
timer = &am335x_timer;
kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_WRITE,
&timer_phys_map, (vir_bytes) & timer->base);
/* disable the module and wait for the module to be disabled */
set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
CM_MODULEMODE_DISABLED);
while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
!= CM_CLKCTRL_IDLEST_DISABLE);
set32(CLKSEL_TIMER1MS_CLK, CLKSEL_TIMER1MS_CLK_SEL_MASK,
CLKSEL_TIMER1MS_CLK_SEL_SEL2);
while ((read32(CLKSEL_TIMER1MS_CLK) &
CLKSEL_TIMER1MS_CLK_SEL_MASK) !=
CLKSEL_TIMER1MS_CLK_SEL_SEL2);
/* enable the module and wait for the module to be ready */
set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
CM_MODULEMODE_ENABLE);
while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
!= CM_CLKCTRL_IDLEST_FUNC);
/* Stop timer */
mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
}
/* Use 1-ms tick mode for GPTIMER1 TRM 16.2.4.2.1 */
mmio_write(timer->base + timer->regs->TPIR, 232000);
mmio_write(timer->base + timer->regs->TNIR, -768000);
mmio_write(timer->base + timer->regs->TLDR,
0xffffffff - (32768 / freq) + 1);
mmio_write(timer->base + timer->regs->TCRR,
0xffffffff - (32768 / freq) + 1);
/* Set up overflow interrupt */
tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
OMAP3_TISR_TCAR_IT_FLAG;
/* Clear interrupt status */
mmio_write(timer->base + timer->regs->TISR, tisr);
mmio_write(timer->base + timer->regs->TIER, OMAP3_TIER_OVF_IT_ENA);
/* Start timer */
mmio_set(timer->base + timer->regs->TCLR,
OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST);
/* also initilize the free runnning timer */
omap3_frclock_init();
}
void
bsp_timer_stop()
{
mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
}
static u32_t
read_frc(void)
{
if (done == 0) {
return 0;
}
return mmio_read(fr_timer->base + fr_timer->regs->TCRR);
}
/*
* Check if the free running clock has overflown and
* increase the high free running clock counter if
* so. This method takes the current timer value as
* parameter to ensure the overflow check is done
* on the current timer value.
*
* To compose the current timer value (64 bits) you
* need to follow the following sequence:
* read the current timer value.
* call the overflow check
* compose the 64 bits time based on the current timer value
* and high_frc.
*/
static void
frc_overflow_check(u32_t cur_frc)
{
static int prev_frc_valid;
static u32_t prev_frc;
if (prev_frc_valid && prev_frc > cur_frc) {
high_frc++;
}
prev_frc = cur_frc;
prev_frc_valid = 1;
}
void
bsp_timer_int_handler()
{
/* Clear all interrupts */
u32_t tisr, now;
/* when the kernel itself is running interrupts are disabled. We
* should therefore also read the overflow counter to detect this as
* to not miss events. */
tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
OMAP3_TISR_TCAR_IT_FLAG;
mmio_write(timer->base + timer->regs->TISR, tisr);
now = read_frc();
frc_overflow_check(now);
}
/* Use the free running clock as TSC */
void
read_tsc_64(u64_t * t)
{
u32_t now;
now = read_frc();
frc_overflow_check(now);
*t = (u64_t) now + (high_frc << 32);
}

View File

@@ -0,0 +1,157 @@
#ifndef _OMAP_TIMER_REGISTERS_H
#define _OMAP_TIMER_REGISTERS_H
/* General-purpose timer register map */
#define OMAP3_GPTIMER1_BASE 0x48318000 /* GPTIMER1 physical address */
#define OMAP3_GPTIMER2_BASE 0x49032000 /* GPTIMER2 physical address */
#define OMAP3_GPTIMER3_BASE 0x49034000 /* GPTIMER3 physical address */
#define OMAP3_GPTIMER4_BASE 0x49036000 /* GPTIMER4 physical address */
#define OMAP3_GPTIMER5_BASE 0x49038000 /* GPTIMER5 physical address */
#define OMAP3_GPTIMER6_BASE 0x4903A000 /* GPTIMER6 physical address */
#define OMAP3_GPTIMER7_BASE 0x4903C000 /* GPTIMER7 physical address */
#define OMAP3_GPTIMER8_BASE 0x4903E000 /* GPTIMER8 physical address */
#define OMAP3_GPTIMER9_BASE 0x49040000 /* GPTIMER9 physical address */
#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */
#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */
/* General-purpose timer registers */
#define OMAP3_TIMER_TIDR 0x000 /* IP revision code */
#define OMAP3_TIMER_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */
#define OMAP3_TIMER_TISTAT 0x014 /* Status (excl. interrupt status) */
#define OMAP3_TIMER_TISR 0x018 /* Pending interrupt status */
#define OMAP3_TIMER_TIER 0x01C /* Interrupt enable */
#define OMAP3_TIMER_TWER 0x020 /* Wakeup enable */
#define OMAP3_TIMER_TCLR 0x024 /* Controls optional features */
#define OMAP3_TIMER_TCRR 0x028 /* Internal counter value */
#define OMAP3_TIMER_TLDR 0x02C /* Timer load value */
#define OMAP3_TIMER_TTGR 0x030 /* Triggers counter reload */
#define OMAP3_TIMER_TWPS 0x034 /* Indicates if Write-Posted pending */
#define OMAP3_TIMER_TMAR 0x038 /* Value to be compared with counter */
#define OMAP3_TIMER_TCAR1 0x03C /* First captured value of counter register */
#define OMAP3_TIMER_TSICR 0x040 /* Control posted mode and functional SW reset */
#define OMAP3_TIMER_TCAR2 0x044 /* Second captured value of counter register */
#define OMAP3_TIMER_TPIR 0x048 /* Positive increment (1 ms tick) */
#define OMAP3_TIMER_TNIR 0x04C /* Negative increment (1 ms tick) */
#define OMAP3_TIMER_TCVR 0x050 /* Defines TCRR is sub/over-period (1 ms tick) */
#define OMAP3_TIMER_TOCR 0x054 /* Masks tick interrupt */
#define OMAP3_TIMER_TOWR 0x058 /* Number of masked overflow interrupts */
#define AM335X_DMTIMER0_BASE 0x44E05000 /* DMTimer0 Registers */
#define AM335X_DMTIMER1_1MS_BASE 0x44E31000 /* DMTimer1 1ms Registers (Accurate 1ms timer) */
#define AM335X_DMTIMER2_BASE 0x48040000 /* DMTimer2 Registers */
#define AM335X_DMTIMER3_BASE 0x48042000 /* DMTimer3 Registers */
#define AM335X_DMTIMER4_BASE 0x48044000 /* DMTimer4 Registers */
#define AM335X_DMTIMER5_BASE 0x48046000 /* DMTimer5 Registers */
#define AM335X_DMTIMER6_BASE 0x48048000 /* DMTimer6 Registers */
#define AM335X_DMTIMER7_BASE 0x4804A000 /* DMTimer7 Registers */
/* General-purpose timer registers AM335x non 1MS timers have different offsets */
#define AM335X_TIMER_TIDR 0x000 /* IP revision code */
#define AM335X_TIMER_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */
#define AM335X_TIMER_IRQSTATUS_RAW 0x024 /* Timer IRQSTATUS Raw Register */
#define AM335X_TIMER_IRQSTATUS 0x028 /* Timer IRQSTATUS Register */
#define AM335X_TIMER_IRQENABLE_SET 0x02C /* Timer IRQENABLE Set Register */
#define AM335X_TIMER_IRQENABLE_CLR 0x030 /* Timer IRQENABLE Clear Register */
#define AM335X_TIMER_IRQWAKEEN 0x034 /* Timer IRQ Wakeup Enable Register */
#define AM335X_TIMER_TCLR 0x038 /* Controls optional features */
#define AM335X_TIMER_TCRR 0x03C /* Internal counter value */
#define AM335X_TIMER_TLDR 0x040 /* Timer load value */
#define AM335X_TIMER_TTGR 0x044 /* Triggers counter reload */
#define AM335X_TIMER_TWPS 0x048 /* Indicates if Write-Posted pending */
#define AM335X_TIMER_TMAR 0x04C /* Value to be compared with counter */
#define AM335X_TIMER_TCAR1 0x050 /* First captured value of counter register */
#define AM335X_TIMER_TSICR 0x054 /* Control posted mode and functional SW reset */
#define AM335X_TIMER_TCAR2 0x058 /* Second captured value of counter register */
#define AM335X_WDT_BASE 0x44E35000 /* watchdog timer */
#define AM335X_WDT_WWPS 0x34 /* command posted status */
#define AM335X_WDT_WSPR 0x48 /* activate/deactivate sequence */
/* Interrupt status register fields */
#define OMAP3_TISR_MAT_IT_FLAG (1 << 0) /* Pending match interrupt status */
#define OMAP3_TISR_OVF_IT_FLAG (1 << 1) /* Pending overflow interrupt status */
#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */
/* Interrupt enable register fields */
#define OMAP3_TIER_MAT_IT_ENA (1 << 0) /* Enable match interrupt */
#define OMAP3_TIER_OVF_IT_ENA (1 << 1) /* Enable overflow interrupt */
#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */
/* Timer control fields */
#define OMAP3_TCLR_ST (1 << 0) /* Start/stop timer */
#define OMAP3_TCLR_AR (1 << 1) /* Autoreload or one-shot mode */
#define OMAP3_TCLR_PRE (1 << 5) /* Prescaler on */
#define OMAP3_TCLR_PTV 2
#define OMAP3_TCLR_OVF_TRG (1 << 10) /* Overflow trigger */
#define OMAP3_CM_CLKSEL_GFX 0x48004b40
#define OMAP3_CM_CLKEN_PLL 0x48004d00
#define OMAP3_CM_FCLKEN1_CORE 0x48004A00
#define OMAP3_CM_CLKSEL_CORE 0x48004A40 /* GPT10 src clock sel. */
#define OMAP3_CM_FCLKEN_PER 0x48005000
#define OMAP3_CM_CLKSEL_PER 0x48005040
#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* GPT1 source clock selection */
#define CM_MODULEMODE_MASK (0x3 << 0)
#define CM_MODULEMODE_ENABLE (0x2 << 0)
#define CM_MODULEMODE_DISABLED (0x0 << 0)
#define CM_CLKCTRL_IDLEST (0x3 << 16)
#define CM_CLKCTRL_IDLEST_FUNC (0x0 << 16)
#define CM_CLKCTRL_IDLEST_TRANS (0x1 << 16)
#define CM_CLKCTRL_IDLEST_IDLE (0x2 << 16)
#define CM_CLKCTRL_IDLEST_DISABLE (0x3 << 16)
#define CM_WKUP_BASE 0x44E00400 /* Clock Module Wakeup Registers */
#define CM_WKUP_TIMER1_CLKCTRL (CM_WKUP_BASE + 0xC4) /* This register manages the TIMER1 clocks. [Memory Mapped] */
#define CM_PER_BASE 0x44E00000 /* Clock Module Peripheral Registers */
#define CM_PER_TIMER7_CLKCTRL (CM_PER_BASE + 0x7C) /* This register manages the TIMER7 clocks. [Memory Mapped] */
/* CM_DPLL registers */
#define CM_DPLL_BASE 0x44E00500 /* Clock Module PLL Registers */
#define CLKSEL_TIMER1MS_CLK (CM_DPLL_BASE + 0x28)
#define CLKSEL_TIMER1MS_CLK_SEL_MASK (0x7 << 0)
#define CLKSEL_TIMER1MS_CLK_SEL_SEL1 (0x0 << 0) /* Select CLK_M_OSC clock */
#define CLKSEL_TIMER1MS_CLK_SEL_SEL2 (0x1 << 0) /* Select CLK_32KHZ clock */
#define CLKSEL_TIMER1MS_CLK_SEL_SEL3 (0x2 << 0) /* Select TCLKIN clock */
#define CLKSEL_TIMER1MS_CLK_SEL_SEL4 (0x3 << 0) /* Select CLK_RC32K clock */
#define CLKSEL_TIMER1MS_CLK_SEL_SEL5 (0x4 << 0) /* Selects the CLK_32768 from 32KHz Crystal Osc */
#define CLKSEL_TIMER7_CLK (CM_DPLL_BASE + 0x04)
#define CLKSEL_TIMER7_CLK_SEL_MASK (0x3 << 0)
#define CLKSEL_TIMER7_CLK_SEL_SEL1 (0x0 << 0) /* Select TCLKIN clock */
#define CLKSEL_TIMER7_CLK_SEL_SEL2 (0x1 << 0) /* Select CLK_M_OSC clock */
#define CLKSEL_TIMER7_CLK_SEL_SEL3 (0x2 << 0) /* Select CLK_32KHZ clock */
#define CLKSEL_TIMER7_CLK_SEL_SEL4 (0x3 << 0) /* Reserved */
#define OMAP3_CLKSEL_GPT1 (1 << 0) /* Selects GPTIMER 1 source
* clock:
*
* 0: use 32KHz clock
* 1: sys clock)
*/
#define OMAP3_CLKSEL_GPT10 (1 << 6)
#define OMAP3_CLKSEL_GPT11 (1 << 7)
#define TIMER_FREQ 1000 /* clock frequency for OMAP timer (1ms) */
#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/
#endif /* _OMAP_TIMER_REGISTERS_H */

View File

@@ -0,0 +1,30 @@
#include "kernel/kernel.h"
#include "direct_utils.h"
#include "bsp_serial.h"
#include "glo.h"
void direct_cls(void)
{
/* Do nothing */
}
void direct_print_char(char c)
{
if(c == '\n')
bsp_ser_putc('\r');
ser_putc(c);
}
void direct_print(const char *str)
{
while (*str) {
direct_print_char(*str);
str++;
}
}
int direct_read_char(unsigned char *ch)
{
return 0;
}

View File

@@ -0,0 +1,18 @@
#include "kernel/system.h"
#include <minix/endpoint.h>
#if USE_PADCONF
/* get arch specific arch_padconf_set() */
#include "bsp_padconf.h"
/*===========================================================================*
* do_padconf *
*===========================================================================*/
int do_padconf(struct proc *caller_ptr, message *m_ptr)
{
return bsp_padconf_set(m_ptr->PADCONF_PADCONF, m_ptr->PADCONF_MASK,
m_ptr->PADCONF_VALUE);
}
#endif /* USE_PADCONF */

View File

@@ -0,0 +1,22 @@
#include <machine/asm.h>
IMPORT(undefined_inst_entry)
IMPORT(svc_entry)
IMPORT(prefetch_abort_entry)
IMPORT(data_abort_entry)
IMPORT(irq_entry)
.text
.balign 4096
LABEL(exc_vector_table)
ldr pc, =invalid_exc /* Reset */
ldr pc, =undefined_inst_entry /* Undefined Instruction */
ldr pc, =svc_entry /* Supervisor Call */
ldr pc, =prefetch_abort_entry /* Prefetch Abort */
ldr pc, =data_abort_entry /* Data Abort */
ldr pc, =invalid_exc /* Hypervisor Call */
ldr pc, =irq_entry /* Interrupt */
ldr pc, =invalid_exc /* Fast Interrupt */
ENTRY(invalid_exc)
b .

View File

@@ -0,0 +1,232 @@
/* This file contains a simple exception handler. Exceptions in user
* processes are converted to signals. Exceptions in a kernel task cause
* a panic.
*/
#include "kernel/kernel.h"
#include "arch_proto.h"
#include <signal.h>
#include <string.h>
#include <assert.h>
#include "kernel/proc.h"
#include "kernel/proto.h"
#include <machine/vm.h>
struct ex_s {
char *msg;
int signum;
};
static struct ex_s ex_data[] = {
{ "Reset", 0},
{ "Undefined instruction", SIGILL},
{ "Supervisor call", 0},
{ "Prefetch Abort", SIGILL},
{ "Data Abort", SIGSEGV},
{ "Hypervisor call", 0},
{ "Interrupt", 0},
{ "Fast Interrupt", 0},
};
static void inkernel_disaster(struct proc *saved_proc,
reg_t *saved_lr, struct ex_s *ep, int is_nested);
extern int catch_pagefaults;
static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc);
static void pagefault( struct proc *pr,
reg_t *saved_lr,
int is_nested,
u32_t pagefault_addr,
u32_t pagefault_status)
{
int in_physcopy = 0, in_memset = 0;
message m_pagefault;
int err;
in_physcopy = (*saved_lr > (vir_bytes) phys_copy) &&
(*saved_lr < (vir_bytes) phys_copy_fault);
in_memset = (*saved_lr > (vir_bytes) phys_memset) &&
(*saved_lr < (vir_bytes) memset_fault);
if((is_nested || iskernelp(pr)) &&
catch_pagefaults && (in_physcopy || in_memset)) {
if (is_nested) {
if(in_physcopy) {
assert(!in_memset);
*saved_lr = (reg_t) phys_copy_fault_in_kernel;
} else {
*saved_lr = (reg_t) memset_fault_in_kernel;
}
}
else {
pr->p_reg.pc = (reg_t) phys_copy_fault;
pr->p_reg.retreg = pagefault_addr;
}
return;
}
if(is_nested) {
printf("pagefault in kernel at pc 0x%lx address 0x%lx\n",
*saved_lr, pagefault_addr);
inkernel_disaster(pr, saved_lr, NULL, is_nested);
}
/* VM can't handle page faults. */
if(pr->p_endpoint == VM_PROC_NR) {
/* Page fault we can't / don't want to
* handle.
*/
printf("pagefault for VM on CPU %d, "
"pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
cpuid, pr->p_reg.pc, pagefault_addr, pagefault_status,
is_nested);
proc_stacktrace(pr);
printf("pc of pagefault: 0x%lx\n", pr->p_reg.pc);
panic("pagefault in VM");
return;
}
/* Don't schedule this process until pagefault is handled. */
RTS_SET(pr, RTS_PAGEFAULT);
/* tell Vm about the pagefault */
m_pagefault.m_source = pr->p_endpoint;
m_pagefault.m_type = VM_PAGEFAULT;
m_pagefault.VPF_ADDR = pagefault_addr;
m_pagefault.VPF_FLAGS = pagefault_status;
if ((err = mini_send(pr, VM_PROC_NR,
&m_pagefault, FROM_KERNEL))) {
panic("WARNING: pagefault: mini_send returned %d\n", err);
}
return;
}
static void inkernel_disaster(struct proc *saved_proc,
reg_t *saved_lr, struct ex_s *ep,
int is_nested)
{
#if USE_SYSDEBUG
if(ep)
printf("\n%s\n", ep->msg);
printf("cpu %d is_nested = %d ", cpuid, is_nested);
if (saved_proc) {
printf("scheduled was: process %d (%s), ", saved_proc->p_endpoint, saved_proc->p_name);
printf("pc = 0x%x\n", (unsigned) saved_proc->p_reg.pc);
proc_stacktrace(saved_proc);
panic("Unhandled kernel exception");
}
/* in an early stage of boot process we don't have processes yet */
panic("exception in kernel while booting, no saved_proc yet");
#endif /* USE_SYSDEBUG */
}
void exception_handler(int is_nested, reg_t *saved_lr, int vector)
{
/* An exception or unexpected interrupt has occurred. */
struct ex_s *ep;
struct proc *saved_proc;
saved_proc = get_cpulocal_var(proc_ptr);
ep = &ex_data[vector];
assert((vir_bytes) saved_lr >= kinfo.vir_kern_start);
/*
* handle special cases for nested problems as they might be tricky or filter
* them out quickly if the traps are not nested
*/
if (is_nested) {
/*
* if a problem occurred while copying a message from userspace because
* of a wrong pointer supplied by userland, handle it the only way we
* can handle it ...
*/
if (((void*)*saved_lr >= (void*)copy_msg_to_user &&
(void*)*saved_lr <= (void*)__copy_msg_to_user_end) ||
((void*)*saved_lr >= (void*)copy_msg_from_user &&
(void*)*saved_lr <= (void*)__copy_msg_from_user_end)) {
switch(vector) {
/* these error are expected */
case DATA_ABORT_VECTOR:
*saved_lr = (reg_t) __user_copy_msg_pointer_failure;
return;
default:
panic("Copy involving a user pointer failed unexpectedly!");
}
}
}
if (vector == DATA_ABORT_VECTOR) {
pagefault(saved_proc, saved_lr, is_nested, read_dfar(), read_dfsr());
return;
}
if (!is_nested && vector == PREFETCH_ABORT_VECTOR) {
reg_t ifar = read_ifar(), ifsr = read_ifsr();
/* The saved_lr is the instruction we're going to execute after
* the fault is handled; IFAR is the address that pagefaulted
* while fetching the instruction. As far as we know the two
* should be the same, if not this assumption will lead to very
* hard to debug problems (instruction executing being off by one)
* and this assumption needs re-examining, hence the assert.
*/
assert(*saved_lr == ifar);
pagefault(saved_proc, saved_lr, is_nested, ifar, ifsr);
return;
}
/* If an exception occurs while running a process, the is_nested variable
* will be zero. Exceptions in interrupt handlers or system traps will make
* is_nested non-zero.
*/
if (is_nested == 0 && ! iskernelp(saved_proc)) {
cause_sig(proc_nr(saved_proc), ep->signum);
return;
}
/* Exception in system code. This is not supposed to happen. */
inkernel_disaster(saved_proc, saved_lr, ep, is_nested);
panic("return from inkernel_disaster");
}
#if USE_SYSDEBUG
/*===========================================================================*
* proc_stacktrace_execute *
*===========================================================================*/
static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc)
{
printf("%-8.8s %6d 0x%lx \n",
whichproc->p_name, whichproc->p_endpoint, pc);
}
#endif
void proc_stacktrace(struct proc *whichproc)
{
#if USE_SYSDEBUG
proc_stacktrace_execute(whichproc, whichproc->p_reg.fp, whichproc->p_reg.pc);
#endif /* USE_SYSDEBUG */
}
void enable_fpu_exception(void)
{
}
void disable_fpu_exception(void)
{
}

View File

@@ -0,0 +1,9 @@
#ifndef __GLO_ARM_H__
#define __GLO_ARM_H__
#include "kernel/kernel.h"
#include "arch_proto.h"
EXTERN struct tss_s tss[CONFIG_MAX_CPUS];
#endif /* __GLO_ARM_H__ */

View File

@@ -0,0 +1,54 @@
#include "kernel/kernel.h" /* configures the kernel */
/* sections */
#include <machine/vm.h>
#include "kernel/kernel.h"
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include <machine/asm.h>
#include <machine/interrupt.h>
#include "archconst.h"
#include "kernel/const.h"
#include "kernel/proc.h"
#include "sconst.h"
#include <machine/multiboot.h>
#include <machine/cpu.h>
#include "arch_proto.h" /* K_STACK_SIZE */
.text
/*===========================================================================*/
/* MINIX */
/*===========================================================================*/
.global MINIX
MINIX:
/* this is the entry point for the MINIX kernel */
b multiboot_init
multiboot_init:
ldr sp, =load_stack_start /* make usable stack */
mov fp, #0
bl _C_LABEL(pre_init)
/* Kernel is mapped high now and ready to go, with
* the boot info pointer returned by pre_init in r0.
* Set the highly mapped stack and initialize it.
*
* Afther that call kmain with r0 still pointing to boot info
*/
ldr sp, =k_initial_stktop
mov r1, #0
push {r1} /* Terminate stack */
ldr r2, =_C_LABEL(kmain) /* r0 holds kinfo_t ptr */
bx r2
/* not reached */
hang:
b hang
.data
load_stack:
.space 4096
load_stack_start:

View File

@@ -0,0 +1,16 @@
/* hw_intr handles the hardware dependent part of the interrupts */
#include "hw_intr.h"
#include "bsp_intr.h"
int hw_intr_mask(int irq){
bsp_irq_mask(irq);
}
int hw_intr_unmask(int irq){
bsp_irq_unmask(irq);
}
int hw_intr_ack(int irq){};
int hw_intr_used(int irq){};
int hw_intr_not_used(int irq){};
int hw_intr_disable_all(){};

View File

@@ -0,0 +1,6 @@
#ifndef __CLOCK_ARM_H__
#define __CLOCK_ARM_H__
void arch_timer_int_handler(void);
#endif /* __CLOCK_ARM_H__ */

View File

@@ -0,0 +1,125 @@
#ifndef _ARM_PROTO_H
#define _ARM_PROTO_H
#include <machine/vm.h>
#define K_STACK_SIZE ARM_PAGE_SIZE
#ifndef __ASSEMBLY__
#include "cpufunc.h"
/* klib */
__dead void reset(void);
phys_bytes vir2phys(void *);
vir_bytes phys_memset(phys_bytes ph, u32_t c, phys_bytes bytes);
void __switch_address_space(struct proc *p, struct proc **__ptproc);
#define switch_address_space(proc) \
__switch_address_space(proc, get_cpulocal_var_ptr(ptproc))
void __copy_msg_from_user_end(void);
void __copy_msg_to_user_end(void);
void __user_copy_msg_pointer_failure(void);
/* multiboot.c */
void multiboot_init(void);
/* protect.c */
struct tss_s {
reg_t sp0; /* stack pointer to use during interrupt */
} __attribute__((packed));
int tss_init(unsigned cpu, void * kernel_stack);
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len);
phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len);
void vm_enable_paging(void);
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end);
phys_bytes pg_roundup(phys_bytes b);
void pg_info(reg_t *, u32_t **);
void pg_clear(void);
void pg_identity(kinfo_t *);
phys_bytes pg_load(void);
void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi);
int pg_mapkernel(void);
void pg_mapproc(struct proc *p, struct boot_image *ip, kinfo_t *cbi);
EXTERN void * k_stacks_start;
extern void * k_stacks;
#define get_k_stack_top(cpu) ((void *)(((char*)(k_stacks)) \
+ 2 * ((cpu) + 1) * K_STACK_SIZE))
/*
* Definition of a callback used when a memory map changed it's base address
*/
typedef int (*kern_phys_map_mapped)(vir_bytes id, vir_bytes new_addr );
/*
* struct used internally by memory.c to keep a list of
* items to map. These should be statically allocated
* in the individual files and passed as argument.
* The data doesn't need to be initialized. See omap_serial for
* and example usage.
*/
typedef struct kern_phys_map{
phys_bytes addr; /* The physical address to map */
vir_bytes size; /* The size of the mapping */
vir_bytes id; /* an id passed to the callback */
int vm_flags; /* flags to be passed to vm map */
kern_phys_map_mapped cb; /* the callback itself */
phys_bytes vir; /* The virtual address once remapped */
int index; /* index */
struct kern_phys_map *next; /* pointer to the next */
} kern_phys_map ;
/*
* Request an in kernel physical mapping.
*
* On ARM many devices are memory mapped and some of these devices
* are used in the kernel. These device can be things like serial
* lines, interrupt controller and clocks. The kernel needs to be
* able to access these devices at the various stages of booting.
* During startup, until arch_enable_paging is called, it is the
* kernel whom is controlling the mappings and it often needs to
* access the memory using a 1:1 mapping between virtual and
* physical memory.
*
* Once processes start to run it is no longer desirable for the
* kernel to have devices mapped in the middle of the process
* address space.
*
* This method requests the memory manager to map base_address/size
* in the kernel address space and call back the kernel when this
* mapping takes effect (after enable_paging).
*
* Before the callback is called it is up to the kernel to use it's
* own addressing. The callback will happen *after* the kernel lost
* it's initial mapping. It it therefore not safe to use the initial
* mapping in the callback. It also is not possible to use printf for
* the same reason.
*/
int kern_req_phys_map( phys_bytes base_address, vir_bytes io_size,
int vm_flags, kern_phys_map * priv,
kern_phys_map_mapped cb, vir_bytes id);
/*
* Request a physical mapping and put the result in the given prt
* Note that ptr will only be valid once the callback happened.
*/
int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size,
int vm_flags, kern_phys_map * priv,
vir_bytes ptr);
void arch_ser_init();
/* functions defined in architecture-independent kernel source. */
#include "kernel/proto.h"
#endif /* __ASSEMBLY__ */
#endif

View File

@@ -0,0 +1,6 @@
#ifndef __ARM_WATCHDOG_H__
#define __ARM_WATCHDOG_H__
#include "kernel/kernel.h"
#endif /* __ARM_WATCHDOG_H__ */

View File

@@ -0,0 +1,41 @@
#ifndef _ARM_ACONST_H
#define _ARM_ACONST_H
#include <machine/interrupt.h>
#include <machine/memory.h>
#include <machine/cpu.h>
#include <arm/armreg.h>
/* Program stack words and masks. */
#define INIT_PSR (PSR_USR32_MODE | PSR_F) /* initial psr */
#define INIT_TASK_PSR (PSR_SVC32_MODE | PSR_F) /* initial psr for tasks */
/* Exception vector numbers */
#define RESET_VECTOR 0
#define UNDEFINED_INST_VECTOR 1
#define SUPERVISOR_CALL_VECTOR 2
#define PREFETCH_ABORT_VECTOR 3
#define DATA_ABORT_VECTOR 4
#define HYPERVISOR_CALL_VECTOR 5
#define INTERRUPT_VECTOR 6
#define FAST_INTERRUPT_VECTOR 7
/*
* defines how many bytes are reserved at the top of the kernel stack for global
* information like currently scheduled process or current cpu id
*/
#define ARM_STACK_TOP_RESERVED (2 * sizeof(reg_t))
/* only selected bits are changeable by user e.g.[31:9] and skip the
* mode bits. It is probably is a better idea to look at the current
* status to determine if one is allowed to write these values. This
* might allow debugging of privileged processes
*/
#define SET_USR_PSR(rp, npsr) \
rp->p_reg.psr = ( rp->p_reg.psr & 0x1F) | ( npsr & ~0x1F)
#define PG_ALLOCATEME ((phys_bytes)-1)
#endif /* _ARM_ACONST_H */

View File

@@ -0,0 +1,22 @@
#ifndef _CCNT_H
#define _CCNT_H
/* ARMV7 PMU (performance monitors) */
/* ARM ARM B4.1.116 */
#define PMU_PMCNTENSET_C (1 << 31) /* Enable PMCCNTR cycle counter */
/* ARM ARM B4.1.117 PMCR */
#define PMU_PMCR_DP (1 << 5) /* Disable when ev. cnt. prohibited */
#define PMU_PMCR_X (1 << 4) /* Export enable */
#define PMU_PMCR_D (1 << 3) /* Clock divider */
#define PMU_PMCR_C (1 << 2) /* Cycle counter reset */
#define PMU_PMCR_P (1 << 1) /* Event counter reset */
#define PMU_PMCR_E (1 << 0) /* Enable event counters */
/* ARM ARM B4.1.119 PMINTENSET */
#define PMU_PMINTENSET_C (1 << 31) /* PMCCNTR overflow int req. enable*/
/* ARM ARM B4.1.124 PMUSERENR */
#define PMU_PMUSERENR_EN (1 << 0) /* User mode access enable bit */
#endif /* _CCNT_H */

View File

@@ -0,0 +1,463 @@
#ifndef _ARM_CPUFUNC_H
#define _ARM_CPUFUNC_H
#if 0
/* check interrupt state */
static inline void check_int(unsigned int state, int line)
{
unsigned int cpsr = 0;
asm volatile("mrs %0, cpsr" : "=r" (cpsr));
if ((cpsr & PSR_F) != (state & PSR_F))
printf("%d: FIQs are unexpectedly %s\n", line, (cpsr & PSR_F) ? "MASKED" : "UNMASKED");
if ((cpsr & PSR_I) != (state & PSR_I))
printf("%d: IRQs are unexpectedly %s\n", line, (cpsr & PSR_I) ? "MASKED" : "UNMASKED");
}
#endif
/* Data memory barrier */
static inline void dmb(void)
{
asm volatile("dmb" : : : "memory");
}
/* Data synchronization barrier */
static inline void dsb(void)
{
asm volatile("dsb" : : : "memory");
}
/* Instruction synchronization barrier */
static inline void isb(void)
{
asm volatile("isb" : : : "memory");
}
static inline void barrier(void)
{
dsb();
isb();
}
/* Read CLIDR, Cache Level ID Register */
static inline u32_t read_clidr(){
u32_t clidr;
asm volatile("mrc p15, 1, %[clidr], c0, c0 , 1 @ READ CLIDR\n\t"
: [clidr] "=r" (clidr));
return clidr;
}
/* Read CSSELR, Cache Size Selection Register */
static inline u32_t read_csselr(){
u32_t csselr;
asm volatile("mrc p15, 2, %[csselr], c0, c0 , 0 @ READ CSSELR\n\t"
: [csselr] "=r" (csselr));
return csselr;
}
/* Write CSSELR, Cache Size Selection Register */
static inline void write_csselr(u32_t csselr){
asm volatile("mcr p15, 2, %[csselr], c0, c0 , 0 @ WRITE CSSELR\n\t"
: : [csselr] "r" (csselr));
}
/* Read Cache Size ID Register */
static inline u32_t read_ccsidr()
{
u32_t ccsidr;
asm volatile("mrc p15, 1, %[ccsidr], c0, c0, 0 @ Read CCSIDR\n\t"
: [ccsidr] "=r" (ccsidr));
return ccsidr;
}
/* Read TLBTR, TLB Type Register */
static inline u32_t read_tlbtr()
{
u32_t tlbtr;
asm volatile("mrc p15, 0, %[tlbtr], c0, c0, 3 @ Read TLBTR\n\t"
: [tlbtr] "=r" (tlbtr));
return tlbtr;
}
/* keesj:move these out */
static inline u32_t ilog2(u32_t t)
{
u32_t counter =0;
while( (t = t >> 1) ) counter ++;
return counter;
}
/* keesj:move these out */
static inline u32_t ipow2(u32_t t)
{
return 1 << t;
}
/*
* type = 1 == CLEAN
* type = 2 == INVALIDATE
*/
static inline void dcache_maint(int type){
u32_t cache_level ;
u32_t clidr;
u32_t ctype;
u32_t ccsidr;
u32_t line_size,line_length;
u32_t number_of_sets,number_of_ways;
u32_t set,way;
clidr = read_clidr();
u32_t loc = ( clidr >> 24) & 0x7;
u32_t louu = ( clidr >> 27) & 0x7;
u32_t louis = ( clidr >> 21) & 0x7;
for (cache_level =0 ; cache_level < loc; cache_level++){
/* get current cache type */
ctype = ( clidr >> cache_level*3) & 0x7;
/* select data or unified or cache level */
write_csselr(cache_level << 1);
isb();
ccsidr = read_ccsidr();
line_size = ccsidr & 0x7;
line_length = 2 << (line_size + 1) ; /* 2**(line_size + 2) */
number_of_sets = ((ccsidr >> 13) & 0x7fff) + 1;
number_of_ways = ((ccsidr >> 3) & 0x3ff) + 1;
u32_t way_bits = ilog2(number_of_ways);
if(ipow2(ilog2(number_of_ways) < number_of_ways) ) {
way_bits++;
}
u32_t l = ilog2(line_length);
for (way =0 ; way < number_of_ways; way++) {
for (set =0 ; set < number_of_sets; set++) {
u32_t val = ( way << (32 - way_bits) ) | (set << l) | (cache_level << 1 );
if (type == 1) {
/* DCCISW, Data Cache Clean and Invalidate by Set/Way */
asm volatile("mcr p15, 0, %[set], c7, c14, 2 @ DCCISW"
: : [set] "r" (val));
} else if (type ==2 ){
/* DCISW, Data Cache Invalidate by Set/Way */
asm volatile("mcr p15, 0, %[set], c7, c6, 2"
: : [set] "r" (val));
}
}
}
}
dsb();
isb();
}
static inline void dcache_clean(){
dcache_maint(1);
}
static inline void dcache_invalidate (){
dcache_maint(2);
}
static inline void refresh_tlb(void)
{
dsb();
/* Invalidate entire unified TLB */
asm volatile("mcr p15, 0, %[zero], c8, c7, 0 @ TLBIALL\n\t" : : [zero] "r" (0));
#if 0
/* Invalidate entire data TLB */
asm volatile("mcr p15, 0, %[zero], c8, c6, 0" : : [zero] "r" (0));
/* Invalidate entire instruction TLB */
asm volatile("mcr p15, 0, %[zero], c8, c5, 0" : : [zero] "r" (0));
#endif
/*
* Invalidate all instruction caches to PoU.
* Also flushes branch target cache.
*/
asm volatile("mcr p15, 0, %[zero], c7, c5, 0" : : [zero] "r" (0));
/* Invalidate entire branch predictor array */
asm volatile("mcr p15, 0, %[zero], c7, c5, 6" : : [zero] "r" (0)); /* flush BTB */
dsb();
isb();
}
/* Read System Control Register */
static inline u32_t read_sctlr()
{
u32_t ctl;
asm volatile("mrc p15, 0, %[ctl], c1, c0, 0 @ Read SCTLR\n\t"
: [ctl] "=r" (ctl));
return ctl;
}
/* Write System Control Register */
static inline void write_sctlr(u32_t ctl)
{
asm volatile("mcr p15, 0, %[ctl], c1, c0, 0 @ Write SCTLR\n\t"
: : [ctl] "r" (ctl));
isb();
}
/* Read Translation Table Base Register 0 */
static inline u32_t read_ttbr0()
{
u32_t bar;
asm volatile("mrc p15, 0, %[bar], c2, c0, 0 @ Read TTBR0\n\t"
: [bar] "=r" (bar));
return bar & ARM_TTBR_ADDR_MASK;
}
/* Write Translation Table Base Register 0 */
static inline void write_ttbr0(u32_t bar)
{
barrier();
/* In our setup TTBR contains the base address *and* the flags
but other pieces of the kernel code expect ttbr to be the
base address of the l1 page table. We therefore add the
flags here and remove them in the read_ttbr0 */
u32_t v = (bar & ARM_TTBR_ADDR_MASK ) | ARM_TTBR_FLAGS_CACHED;
asm volatile("mcr p15, 0, %[bar], c2, c0, 0 @ Write TTBR0\n\t"
: : [bar] "r" (v));
refresh_tlb();
}
/* Reload Translation Table Base Register 0 */
static inline void reload_ttbr0(void)
{
reg_t ttbr = read_ttbr0();
write_ttbr0(ttbr);
}
/* Read Translation Table Base Register 1 */
static inline u32_t read_ttbr1()
{
u32_t bar;
asm volatile("mrc p15, 0, %[bar], c2, c0, 1 @ Read TTBR1\n\t"
: [bar] "=r" (bar));
return bar;
}
/* Write Translation Table Base Register 1 */
static inline void write_ttbr1(u32_t bar)
{
barrier();
asm volatile("mcr p15, 0, %[bar], c2, c0, 1 @ Write TTBR1\n\t"
: : [bar] "r" (bar));
refresh_tlb();
}
/* Reload Translation Table Base Register 1 */
static inline void reload_ttbr1(void)
{
reg_t ttbr = read_ttbr1();
write_ttbr1(ttbr);
}
/* Read Translation Table Base Control Register */
static inline u32_t read_ttbcr()
{
u32_t bcr;
asm volatile("mrc p15, 0, %[bcr], c2, c0, 2 @ Read TTBCR\n\t"
: [bcr] "=r" (bcr));
return bcr;
}
/* Write Translation Table Base Control Register */
static inline void write_ttbcr(u32_t bcr)
{
asm volatile("mcr p15, 0, %[bcr], c2, c0, 2 @ Write TTBCR\n\t"
: : [bcr] "r" (bcr));
isb();
}
/* Read Domain Access Control Register */
static inline u32_t read_dacr()
{
u32_t dacr;
asm volatile("mrc p15, 0, %[dacr], c3, c0, 0 @ Read DACR\n\t"
: [dacr] "=r" (dacr));
return dacr;
}
/* Write Domain Access Control Register */
static inline void write_dacr(u32_t dacr)
{
asm volatile("mcr p15, 0, %[dacr], c3, c0, 0 @ Write DACR\n\t"
: : [dacr] "r" (dacr));
isb();
}
/* Read Data Fault Status Register */
static inline u32_t read_dfsr()
{
u32_t fsr;
asm volatile("mrc p15, 0, %[fsr], c5, c0, 0 @ Read DFSR\n\t"
: [fsr] "=r" (fsr));
return fsr;
}
/* Write Data Fault Status Register */
static inline void write_dfsr(u32_t fsr)
{
asm volatile("mcr p15, 0, %[fsr], c5, c0, 0 @ Write DFSR\n\t"
: : [fsr] "r" (fsr));
isb();
}
/* Read Instruction Fault Status Register */
static inline u32_t read_ifsr()
{
u32_t fsr;
asm volatile("mrc p15, 0, %[fsr], c5, c0, 1 @ Read IFSR\n\t"
: [fsr] "=r" (fsr));
return fsr;
}
/* Write Instruction Fault Status Register */
static inline void write_ifsr(u32_t fsr)
{
asm volatile("mcr p15, 0, %[fsr], c5, c0, 1 @ Write IFSR\n\t"
: : [fsr] "r" (fsr));
isb();
}
/* Read Data Fault Address Register */
static inline u32_t read_dfar()
{
u32_t far;
asm volatile("mrc p15, 0, %[far], c6, c0, 0 @ Read DFAR\n\t"
: [far] "=r" (far));
return far;
}
/* Write Data Fault Address Register */
static inline void write_dfar(u32_t far)
{
asm volatile("mcr p15, 0, %[far], c6, c0, 0 @ Write DFAR\n\t"
: : [far] "r" (far));
isb();
}
/* Read Instruction Fault Address Register */
static inline u32_t read_ifar()
{
u32_t far;
asm volatile("mrc p15, 0, %[far], c6, c0, 2 @ Read IFAR\n\t"
: [far] "=r" (far));
return far;
}
/* Write Instruction Fault Address Register */
static inline void write_ifar(u32_t far)
{
asm volatile("mcr p15, 0, %[far], c6, c0, 2 @ Write IFAR\n\t"
: : [far] "r" (far));
isb();
}
/* Read Vector Base Address Register */
static inline u32_t read_vbar()
{
u32_t vbar;
asm volatile("mrc p15, 0, %[vbar], c12, c0, 0 @ Read VBAR\n\t"
: [vbar] "=r" (vbar));
return vbar;
}
/* Write Vector Base Address Register */
static inline void write_vbar(u32_t vbar)
{
asm volatile("mcr p15, 0, %[vbar], c12, c0, 0 @ Write VBAR\n\t"
: : [vbar] "r" (vbar));
isb();
}
/* Read the Main ID Register */
static inline u32_t read_midr()
{
u32_t id;
asm volatile("mrc p15, 0, %[id], c0, c0, 0 @ read MIDR\n\t"
: [id] "=r" (id));
return id;
}
/* Read Auxiliary Control Register */
static inline u32_t read_actlr()
{
u32_t ctl;
asm volatile("mrc p15, 0, %[ctl], c1, c0, 1 @ Read ACTLR\n\t"
: [ctl] "=r" (ctl));
return ctl;
}
/* Write Auxiliary Control Register */
static inline void write_actlr(u32_t ctl)
{
//http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344k/Babjbjbb.html
asm volatile("mcr p15, 0, %[ctl], c1, c0, 1 @ Write ACTLR\n\t"
: : [ctl] "r" (ctl));
isb();
}
/* Read Current Program Status Register */
static inline u32_t read_cpsr()
{
u32_t status;
asm volatile("mrs %[status], cpsr @ read CPSR"
: [status] "=r" (status));
return status;
}
/* Write Current Program Status Register */
static inline void write_cpsr(u32_t status)
{
asm volatile("msr cpsr_c, %[status] @ write CPSR"
: : [status] "r" (status));
}
#endif /* _ARM_CPUFUNC_H */

View File

@@ -0,0 +1,11 @@
#ifndef MB_UTILS_H
#define MB_UTILS_H
#include "kernel/kernel.h"
void direct_cls(void);
void direct_print(const char*);
void direct_print_char(char);
int direct_read_char(unsigned char*);
#endif

View File

@@ -0,0 +1,15 @@
#ifndef __HW_INTR_ARM_H__
#define __HW_INTR_ARM_H__
#include "kernel/kernel.h"
void irq_handle(int irq);
int hw_intr_mask(int irq);
int hw_intr_unmask(int irq);
int hw_intr_ack(int irq);
int hw_intr_used(int irq);
int hw_intr_not_used(int irq);
int hw_intr_disable_all();
#endif /* __HW_INTR_ARM_H__ */

View File

@@ -0,0 +1,16 @@
#ifndef _ARM_IO_H_
#define _ARM_IO_H_
#ifndef __ASSEMBLY__
#include <sys/types.h>
/* Access memory-mapped I/O devices */
#define mmio_read(a) (*(volatile u32_t *)(a))
#define mmio_write(a,v) (*(volatile u32_t *)(a) = (v))
#define mmio_set(a,v) mmio_write((a), mmio_read((a)) | (v))
#define mmio_clear(a,v) mmio_write((a), mmio_read((a)) & ~(v))
#endif /* __ASSEMBLY__ */
#endif /* _ARM_IO_H_ */

View File

@@ -0,0 +1,50 @@
OUTPUT_ARCH("arm")
ENTRY(__k_unpaged_MINIX)
_kern_phys_base = 0x80200000; /* phys 4MB aligned for convenient remapping */
_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */
_kern_offset = (_kern_vir_base - _kern_phys_base);
__k_unpaged__kern_offset = _kern_offset;
__k_unpaged__kern_vir_base = _kern_vir_base;
__k_unpaged__kern_phys_base = _kern_phys_base;
SECTIONS
{
. = _kern_phys_base;
__k_unpaged__kern_unpaged_start = .;
.unpaged_text ALIGN(4096) : { unpaged_*.o(.text) }
.unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) }
__k_unpaged__kern_unpaged_edata = .;
.unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) }
__k_unpaged__kern_unpaged_end = .;
. += _kern_offset;
. = ALIGN(4096); usermapped_start = .;
.usermapped_glo : AT(ADDR(.usermapped_glo) - _kern_offset) { *(.usermapped_glo) }
. = ALIGN(4096); usermapped_nonglo_start = .;
.usermapped : AT(ADDR(.usermapped) - _kern_offset) { *(.usermapped) }
. = ALIGN(4096); usermapped_end = .;
.text : AT(ADDR(.text) - _kern_offset) { *(.text*) }
_etext = .;
.data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) }
. = ALIGN(4096);
_edata = .;
__k_unpaged__edata = . - _kern_offset;
.bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON)
__k_unpaged__kern_size = . - _kern_vir_base;
_kern_size = __k_unpaged__kern_size;
. += 4096;
}
_end = .;
__k_unpaged__end = . - _kern_offset;
/DISCARD/ :
{
*(.ARM.exidx*)
}
}

View File

@@ -0,0 +1,107 @@
/* sections */
#include <minix/config.h>
#include <minix/const.h>
#include <machine/asm.h>
#include <machine/interrupt.h>
#include <machine/vm.h>
#include "archconst.h"
#include "kernel/const.h"
#include "sconst.h"
#include <machine/multiboot.h>
/*===========================================================================*/
/* copy_msg_from_user */
/*===========================================================================*/
/*
* int copy_msg_from_user(message * user_mbuf, message * dst);
*
* Copies a message of 64 bytes from user process space to a kernel buffer. This
* function assumes that the process address space is installed (ttbr loaded).
*
* This function from the callers point of view either succeeds or returns an
* error which gives the caller a chance to respond accordingly. In fact it
* either succeeds or if it generates a pagefault, general protection or other
* exception, the trap handler has to redirect the execution to
* __user_copy_msg_pointer_failure where the error is reported to the caller
* without resolving the pagefault. It is not kernel's problem to deal with
* wrong pointers from userspace and the caller should return an error to
* userspace as if wrong values or request were passed to the kernel
*/
ENTRY(copy_msg_from_user)
push {r4-r10, lr}
/* load the source pointer */
mov r9, r0
/* load the destination pointer */
mov r10, r1
/* do the copy, first 32 bytes */
ldm r9, {r0-r7}
stm r10, {r0-r7}
/* next 32 bytes */
add r9, r9, #32
add r10, r10, #32
ldm r9, {r0-r7}
stm r10, {r0-r7}
LABEL(__copy_msg_from_user_end)
pop {r4-r10, lr}
mov r0, #0
bx lr
/*===========================================================================*/
/* copy_msg_to_user */
/*===========================================================================*/
/*
* void copy_msg_to_user(message * src, message * user_mbuf);
*
* Copies a message of 64 bytes to user process space from a kernel buffer.
*
* All the other copy_msg_from_user() comments apply here as well!
*/
ENTRY(copy_msg_to_user)
push {r4-r10, lr}
/* load the source pointer */
mov r9, r0
/* load the destination pointer */
mov r10, r1
/* do the copy, first 32 bytes */
ldm r9, {r0-r7}
stm r10, {r0-r7}
/* next 32 bytes */
add r9, r9, #32
add r10, r10, #32
ldm r9, {r0-r7}
stm r10, {r0-r7}
LABEL(__copy_msg_to_user_end)
pop {r4-r10, lr}
mov r0, #0
bx lr
/*
* if a function from a selected set of copies from or to userspace fails, it is
* because of a wrong pointer supplied by the userspace. We have to clean up and
* and return -1 to indicated that something wrong has happend. The place it was
* called from has to handle this situation. The exception handler redirect us
* here to continue, clean up and report the error
*/
ENTRY(__user_copy_msg_pointer_failure)
pop {r4-r10, lr}
mov r0, #-1
bx lr
ENTRY(intr_enable)
ENTRY(interrupts_enable)
dsb
cpsie if
bx lr
ENTRY(intr_disable)
ENTRY(interrupts_disable)
dsb
cpsid if
bx lr

View File

@@ -0,0 +1,899 @@
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include <machine/vm.h>
#include <minix/type.h>
#include <minix/board.h>
#include <minix/syslib.h>
#include <minix/cpufeature.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <machine/vm.h>
#include "arch_proto.h"
#include "kernel/proto.h"
#include "kernel/debug.h"
#include "bsp_timer.h"
#define HASPT(procptr) ((procptr)->p_seg.p_ttbr != 0)
static int nfreepdes = 0;
#define MAXFREEPDES 2
static int freepdes[MAXFREEPDES];
static u32_t phys_get32(phys_bytes v);
/* list of requested physical mapping */
static kern_phys_map *kern_phys_map_head;
void mem_clear_mapcache(void)
{
int i;
for(i = 0; i < nfreepdes; i++) {
struct proc *ptproc = get_cpulocal_var(ptproc);
int pde = freepdes[i];
u32_t *ptv;
assert(ptproc);
ptv = ptproc->p_seg.p_ttbr_v;
assert(ptv);
ptv[pde] = 0;
}
}
/* This function sets up a mapping from within the kernel's address
* space to any other area of memory, either straight physical
* memory (pr == NULL) or a process view of memory, in 1MB windows.
* I.e., it maps in 1MB chunks of virtual (or physical) address space
* to 1MB chunks of kernel virtual address space.
*
* It recognizes pr already being in memory as a special case (no
* mapping required).
*
* The target (i.e. in-kernel) mapping area is one of the freepdes[]
* VM has earlier already told the kernel about that is available. It is
* identified as the 'pde' parameter. This value can be chosen freely
* by the caller, as long as it is in range (i.e. 0 or higher and corresponds
* to a known freepde slot). It is up to the caller to keep track of which
* freepde's are in use, and to determine which ones are free to use.
*
* The logical number supplied by the caller is translated into an actual
* pde number to be used, and a pointer to it (linear address) is returned
* for actual use by phys_copy or memset.
*/
static phys_bytes createpde(
const struct proc *pr, /* Requested process, NULL for physical. */
const phys_bytes linaddr,/* Address after segment translation. */
phys_bytes *bytes, /* Size of chunk, function may truncate it. */
int free_pde_idx, /* index of the free slot to use */
int *changed /* If mapping is made, this is set to 1. */
)
{
u32_t pdeval;
phys_bytes offset;
int pde;
assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes);
pde = freepdes[free_pde_idx];
assert(pde >= 0 && pde < 4096);
if(pr && ((pr == get_cpulocal_var(ptproc)) || iskernelp(pr))) {
/* Process memory is requested, and
* it's a process that is already in current page table, or
* the kernel, which is always there.
* Therefore linaddr is valid directly, with the requested
* size.
*/
return linaddr;
}
if(pr) {
/* Requested address is in a process that is not currently
* accessible directly. Grab the PDE entry of that process'
* page table that corresponds to the requested address.
*/
assert(pr->p_seg.p_ttbr_v);
pdeval = pr->p_seg.p_ttbr_v[ARM_VM_PDE(linaddr)];
} else {
/* Requested address is physical. Make up the PDE entry. */
assert (linaddr >= PHYS_MEM_BEGIN && linaddr <= PHYS_MEM_END);
/* memory */
pdeval = (linaddr & ARM_VM_SECTION_MASK)
| ARM_VM_SECTION
| ARM_VM_SECTION_DOMAIN
| ARM_VM_SECTION_CACHED
| ARM_VM_SECTION_USER;
}
/* Write the pde value that we need into a pde that the kernel
* can access, into the currently loaded page table so it becomes
* visible.
*/
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
if(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v[pde] != pdeval) {
get_cpulocal_var(ptproc)->p_seg.p_ttbr_v[pde] = pdeval;
*changed = 1;
}
/* Memory is now available, but only the 1MB window of virtual
* address space that we have mapped; calculate how much of
* the requested range is visible and return that in *bytes,
* if that is less than the requested range.
*/
offset = linaddr & ARM_VM_OFFSET_MASK_1MB; /* Offset in 1MB window. */
*bytes = MIN(*bytes, ARM_SECTION_SIZE - offset);
/* Return the linear address of the start of the new mapping. */
return ARM_SECTION_SIZE*pde + offset;
}
/*===========================================================================*
* check_resumed_caller *
*===========================================================================*/
static int check_resumed_caller(struct proc *caller)
{
/* Returns the result from VM if caller was resumed, otherwise OK. */
if (caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
assert(caller->p_vmrequest.vmresult != VMSUSPEND);
return caller->p_vmrequest.vmresult;
}
return OK;
}
/*===========================================================================*
* lin_lin_copy *
*===========================================================================*/
static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes)
{
u32_t addr;
proc_nr_t procslot;
assert(get_cpulocal_var(ptproc));
assert(get_cpulocal_var(proc_ptr));
assert(read_ttbr0() == get_cpulocal_var(ptproc)->p_seg.p_ttbr);
procslot = get_cpulocal_var(ptproc)->p_nr;
assert(procslot >= 0 && procslot < ARM_VM_DIR_ENTRIES);
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE));
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_VMINHIBIT));
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_VMINHIBIT));
while(bytes > 0) {
phys_bytes srcptr, dstptr;
vir_bytes chunk = bytes;
int changed = 0;
#ifdef CONFIG_SMP
unsigned cpu = cpuid;
if (srcproc && GET_BIT(srcproc->p_stale_tlb, cpu)) {
changed = 1;
UNSET_BIT(srcproc->p_stale_tlb, cpu);
}
if (dstproc && GET_BIT(dstproc->p_stale_tlb, cpu)) {
changed = 1;
UNSET_BIT(dstproc->p_stale_tlb, cpu);
}
#endif
/* Set up 1MB ranges. */
srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed);
dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed);
if(changed) {
reload_ttbr0();
}
/* Copy pages. */
PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr);
if(addr) {
/* If addr is nonzero, a page fault was caught.
*
* phys_copy does all memory accesses word-aligned (rounded
* down), so pagefaults can occur at a lower address than
* the specified offsets. compute the lower bounds for sanity
* check use.
*/
vir_bytes src_aligned = srcptr & ~0x3, dst_aligned = dstptr & ~0x3;
if(addr >= src_aligned && addr < (srcptr + chunk)) {
return EFAULT_SRC;
}
if(addr >= dst_aligned && addr < (dstptr + chunk)) {
return EFAULT_DST;
}
panic("lin_lin_copy fault out of range");
/* Not reached. */
return EFAULT;
}
/* Update counter and addresses for next iteration, if any. */
bytes -= chunk;
srclinaddr += chunk;
dstlinaddr += chunk;
}
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE));
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
return OK;
}
static u32_t phys_get32(phys_bytes addr)
{
u32_t v;
int r;
if((r=lin_lin_copy(NULL, addr,
proc_addr(SYSTEM), (phys_bytes) &v, sizeof(v))) != OK) {
panic("lin_lin_copy for phys_get32 failed: %d", r);
}
return v;
}
/*===========================================================================*
* umap_virtual *
*===========================================================================*/
phys_bytes umap_virtual(rp, seg, vir_addr, bytes)
register struct proc *rp; /* pointer to proc table entry for process */
int seg; /* T, D, or S segment */
vir_bytes vir_addr; /* virtual address in bytes within the seg */
vir_bytes bytes; /* # of bytes to be copied */
{
phys_bytes phys = 0;
if(vm_lookup(rp, vir_addr, &phys, NULL) != OK) {
printf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%x: 0x%lx failed\n", rp->p_name, seg, vir_addr);
phys = 0;
} else {
if(phys == 0)
panic("vm_lookup returned phys: 0x%lx", phys);
}
if(phys == 0) {
printf("SYSTEM:umap_virtual: lookup failed\n");
return 0;
}
/* Now make sure addresses are contiguous in physical memory
* so that the umap makes sense.
*/
if(bytes > 0 && vm_lookup_range(rp, vir_addr, NULL, bytes) != bytes) {
printf("umap_virtual: %s: %lu at 0x%lx (vir 0x%lx) not contiguous\n",
rp->p_name, bytes, vir_addr, vir_addr);
return 0;
}
/* phys must be larger than 0 (or the caller will think the call
* failed), and address must not cross a page boundary.
*/
assert(phys);
return phys;
}
/*===========================================================================*
* vm_lookup *
*===========================================================================*/
int vm_lookup(const struct proc *proc, const vir_bytes virtual,
phys_bytes *physical, u32_t *ptent)
{
u32_t *root, *pt;
int pde, pte;
u32_t pde_v, pte_v;
assert(proc);
assert(physical);
assert(!isemptyp(proc));
assert(HASPT(proc));
/* Retrieve page directory entry. */
root = (u32_t *) (proc->p_seg.p_ttbr & ARM_TTBR_ADDR_MASK);
assert(!((u32_t) root % ARM_PAGEDIR_SIZE));
pde = ARM_VM_PDE(virtual);
assert(pde >= 0 && pde < ARM_VM_DIR_ENTRIES);
pde_v = phys_get32((u32_t) (root + pde));
if(! ((pde_v & ARM_VM_PDE_PRESENT)
|| (pde_v & ARM_VM_SECTION_PRESENT)
)) {
return EFAULT;
}
if(pde_v & ARM_VM_SECTION) {
*physical = pde_v & ARM_VM_SECTION_MASK;
if(ptent) *ptent = pde_v;
*physical += virtual & ARM_VM_OFFSET_MASK_1MB;
} else {
/* Retrieve page table entry. */
pt = (u32_t *) (pde_v & ARM_VM_PDE_MASK);
assert(!((u32_t) pt % ARM_PAGETABLE_SIZE));
pte = ARM_VM_PTE(virtual);
assert(pte >= 0 && pte < ARM_VM_PT_ENTRIES);
pte_v = phys_get32((u32_t) (pt + pte));
if(!(pte_v & ARM_VM_PTE_PRESENT)) {
return EFAULT;
}
if(ptent) *ptent = pte_v;
/* Actual address now known; retrieve it and add page offset. */
*physical = pte_v & ARM_VM_PTE_MASK;
*physical += virtual % ARM_PAGE_SIZE;
}
return OK;
}
/*===========================================================================*
* vm_lookup_range *
*===========================================================================*/
size_t vm_lookup_range(const struct proc *proc, vir_bytes vir_addr,
phys_bytes *phys_addr, size_t bytes)
{
/* Look up the physical address corresponding to linear virtual address
* 'vir_addr' for process 'proc'. Return the size of the range covered
* by contiguous physical memory starting from that address; this may
* be anywhere between 0 and 'bytes' inclusive. If the return value is
* nonzero, and 'phys_addr' is non-NULL, 'phys_addr' will be set to the
* base physical address of the range. 'vir_addr' and 'bytes' need not
* be page-aligned, but the caller must have verified that the given
* linear range is valid for the given process at all.
*/
phys_bytes phys, next_phys;
size_t len;
assert(proc);
assert(bytes > 0);
assert(HASPT(proc));
/* Look up the first page. */
if (vm_lookup(proc, vir_addr, &phys, NULL) != OK)
return 0;
if (phys_addr != NULL)
*phys_addr = phys;
len = ARM_PAGE_SIZE - (vir_addr % ARM_PAGE_SIZE);
vir_addr += len;
next_phys = phys + len;
/* Look up any next pages and test physical contiguity. */
while (len < bytes) {
if (vm_lookup(proc, vir_addr, &phys, NULL) != OK)
break;
if (next_phys != phys)
break;
len += ARM_PAGE_SIZE;
vir_addr += ARM_PAGE_SIZE;
next_phys += ARM_PAGE_SIZE;
}
/* We might now have overshot the requested length somewhat. */
return MIN(bytes, len);
}
/*===========================================================================*
* vm_suspend *
*===========================================================================*/
static void vm_suspend(struct proc *caller, const struct proc *target,
const vir_bytes linaddr, const vir_bytes len, const int type,
const int writeflag)
{
/* This range is not OK for this process. Set parameters
* of the request and notify VM about the pending request.
*/
assert(!RTS_ISSET(caller, RTS_VMREQUEST));
assert(!RTS_ISSET(target, RTS_VMREQUEST));
RTS_SET(caller, RTS_VMREQUEST);
caller->p_vmrequest.req_type = VMPTYPE_CHECK;
caller->p_vmrequest.target = target->p_endpoint;
caller->p_vmrequest.params.check.start = linaddr;
caller->p_vmrequest.params.check.length = len;
caller->p_vmrequest.params.check.writeflag = writeflag;
caller->p_vmrequest.type = type;
/* Connect caller on vmrequest wait queue. */
if(!(caller->p_vmrequest.nextrequestor = vmrequest))
if(OK != send_sig(VM_PROC_NR, SIGKMEM))
panic("send_sig failed");
vmrequest = caller;
}
/*===========================================================================*
* vm_check_range *
*===========================================================================*/
int vm_check_range(struct proc *caller, struct proc *target,
vir_bytes vir_addr, size_t bytes, int writeflag)
{
/* Public interface to vm_suspend(), for use by kernel calls. On behalf
* of 'caller', call into VM to check linear virtual address range of
* process 'target', starting at 'vir_addr', for 'bytes' bytes. This
* function assumes that it will called twice if VM returned an error
* the first time (since nothing has changed in that case), and will
* then return the error code resulting from the first call. Upon the
* first call, a non-success error code is returned as well.
*/
int r;
if ((caller->p_misc_flags & MF_KCALL_RESUME) &&
(r = caller->p_vmrequest.vmresult) != OK)
return r;
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL,
writeflag);
return VMSUSPEND;
}
/*===========================================================================*
* delivermsg *
*===========================================================================*/
void delivermsg(struct proc *rp)
{
int r = OK;
assert(rp->p_misc_flags & MF_DELIVERMSG);
assert(rp->p_delivermsg.m_source != NONE);
if (copy_msg_to_user(&rp->p_delivermsg,
(message *) rp->p_delivermsg_vir)) {
printf("WARNING wrong user pointer 0x%08lx from "
"process %s / %d\n",
rp->p_delivermsg_vir,
rp->p_name,
rp->p_endpoint);
r = EFAULT;
}
/* Indicate message has been delivered; address is 'used'. */
rp->p_delivermsg.m_source = NONE;
rp->p_misc_flags &= ~MF_DELIVERMSG;
if(!(rp->p_misc_flags & MF_CONTEXT_SET)) {
rp->p_reg.retreg = r;
}
}
/*===========================================================================*
* vmmemset *
*===========================================================================*/
int vm_memset(struct proc* caller, endpoint_t who, phys_bytes ph, int c,
phys_bytes count)
{
u32_t pattern;
struct proc *whoptr = NULL;
phys_bytes cur_ph = ph;
phys_bytes left = count;
phys_bytes ptr, chunk, pfa = 0;
int new_ttbr, r = OK;
if ((r = check_resumed_caller(caller)) != OK)
return r;
/* NONE for physical, otherwise virtual */
if (who != NONE && !(whoptr = endpoint_lookup(who)))
return ESRCH;
c &= 0xFF;
pattern = c | (c << 8) | (c << 16) | (c << 24);
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
assert(!catch_pagefaults);
catch_pagefaults = 1;
/* We can memset as many bytes as we have remaining,
* or as many as remain in the 1MB chunk we mapped in.
*/
while (left > 0) {
new_ttbr = 0;
chunk = left;
ptr = createpde(whoptr, cur_ph, &chunk, 0, &new_ttbr);
if (new_ttbr) {
reload_ttbr0();
}
/* If a page fault happens, pfa is non-null */
if ((pfa = phys_memset(ptr, pattern, chunk))) {
/* If a process pagefaults, VM may help out */
if (whoptr) {
vm_suspend(caller, whoptr, ph, count,
VMSTYPE_KERNELCALL, 1);
assert(catch_pagefaults);
catch_pagefaults = 0;
return VMSUSPEND;
}
/* Pagefault when phys copying ?! */
panic("vm_memset: pf %lx addr=%lx len=%lu\n",
pfa , ptr, chunk);
}
cur_ph += chunk;
left -= chunk;
}
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
assert(catch_pagefaults);
catch_pagefaults = 0;
return OK;
}
/*===========================================================================*
* virtual_copy_f *
*===========================================================================*/
int virtual_copy_f(caller, src_addr, dst_addr, bytes, vmcheck)
struct proc * caller;
struct vir_addr *src_addr; /* source virtual address */
struct vir_addr *dst_addr; /* destination virtual address */
vir_bytes bytes; /* # of bytes to copy */
int vmcheck; /* if nonzero, can return VMSUSPEND */
{
/* Copy bytes from virtual address src_addr to virtual address dst_addr. */
struct vir_addr *vir_addr[2]; /* virtual source and destination address */
int i, r;
struct proc *procs[2];
assert((vmcheck && caller) || (!vmcheck && !caller));
/* Check copy count. */
if (bytes <= 0) return(EDOM);
/* Do some more checks and map virtual addresses to physical addresses. */
vir_addr[_SRC_] = src_addr;
vir_addr[_DST_] = dst_addr;
for (i=_SRC_; i<=_DST_; i++) {
endpoint_t proc_e = vir_addr[i]->proc_nr_e;
int proc_nr;
struct proc *p;
if(proc_e == NONE) {
p = NULL;
} else {
if(!isokendpt(proc_e, &proc_nr)) {
printf("virtual_copy: no reasonable endpoint\n");
return ESRCH;
}
p = proc_addr(proc_nr);
}
procs[i] = p;
}
if ((r = check_resumed_caller(caller)) != OK)
return r;
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {
int writeflag;
struct proc *target = NULL;
phys_bytes lin;
if(r != EFAULT_SRC && r != EFAULT_DST)
panic("lin_lin_copy failed: %d", r);
if(!vmcheck || !caller) {
return r;
}
if(r == EFAULT_SRC) {
lin = vir_addr[_SRC_]->offset;
target = procs[_SRC_];
writeflag = 0;
} else if(r == EFAULT_DST) {
lin = vir_addr[_DST_]->offset;
target = procs[_DST_];
writeflag = 1;
} else {
panic("r strange: %d", r);
}
assert(caller);
assert(target);
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL, writeflag);
return VMSUSPEND;
}
return OK;
}
/*===========================================================================*
* data_copy *
*===========================================================================*/
int data_copy(const endpoint_t from_proc, const vir_bytes from_addr,
const endpoint_t to_proc, const vir_bytes to_addr,
size_t bytes)
{
struct vir_addr src, dst;
src.offset = from_addr;
dst.offset = to_addr;
src.proc_nr_e = from_proc;
dst.proc_nr_e = to_proc;
assert(src.proc_nr_e != NONE);
assert(dst.proc_nr_e != NONE);
return virtual_copy(&src, &dst, bytes);
}
/*===========================================================================*
* data_copy_vmcheck *
*===========================================================================*/
int data_copy_vmcheck(struct proc * caller,
const endpoint_t from_proc, const vir_bytes from_addr,
const endpoint_t to_proc, const vir_bytes to_addr,
size_t bytes)
{
struct vir_addr src, dst;
src.offset = from_addr;
dst.offset = to_addr;
src.proc_nr_e = from_proc;
dst.proc_nr_e = to_proc;
assert(src.proc_nr_e != NONE);
assert(dst.proc_nr_e != NONE);
return virtual_copy_vmcheck(caller, &src, &dst, bytes);
}
void memory_init(void)
{
assert(nfreepdes == 0);
freepdes[nfreepdes++] = kinfo.freepde_start++;
freepdes[nfreepdes++] = kinfo.freepde_start++;
assert(kinfo.freepde_start < ARM_VM_DIR_ENTRIES);
assert(nfreepdes == 2);
assert(nfreepdes <= MAXFREEPDES);
}
/*===========================================================================*
* arch_proc_init *
*===========================================================================*/
void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp,
const u32_t ps_str, char *name)
{
arch_proc_reset(pr);
strcpy(pr->p_name, name);
/* set custom state we know */
pr->p_reg.pc = ip;
pr->p_reg.sp = sp;
pr->p_reg.retreg = ps_str; /* a.k.a r0*/
}
static int usermapped_glo_index = -1,
usermapped_index = -1, first_um_idx = -1;
/* defined in kernel.lds */
extern char usermapped_start, usermapped_end, usermapped_nonglo_start;
int arch_phys_map(const int index,
phys_bytes *addr,
phys_bytes *len,
int *flags)
{
static int first = 1;
kern_phys_map *phys_maps;
int freeidx = 0;
u32_t glo_len = (u32_t) &usermapped_nonglo_start -
(u32_t) &usermapped_start;
if(first) {
memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
if(glo_len > 0) {
usermapped_glo_index = freeidx++;
}
usermapped_index = freeidx++;
first_um_idx = usermapped_index;
if(usermapped_glo_index != -1)
first_um_idx = usermapped_glo_index;
first = 0;
/* list over the maps and index them */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
phys_maps->index = freeidx++;
phys_maps = phys_maps->next;
}
}
if(index == usermapped_glo_index) {
*addr = vir2phys(&usermapped_start);
*len = glo_len;
*flags = VMMF_USER | VMMF_GLO;
return OK;
}
else if(index == usermapped_index) {
*addr = vir2phys(&usermapped_nonglo_start);
*len = (u32_t) &usermapped_end -
(u32_t) &usermapped_nonglo_start;
*flags = VMMF_USER;
return OK;
}
/* if this all fails loop over the maps */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
if(phys_maps->index == index){
*addr = phys_maps->addr;
*len = phys_maps->size;
*flags = phys_maps->vm_flags;
return OK;
}
phys_maps = phys_maps->next;
}
return EINVAL;
}
int arch_phys_map_reply(const int index, const vir_bytes addr)
{
kern_phys_map *phys_maps;
if(index == first_um_idx) {
u32_t usermapped_offset;
assert(addr > (u32_t) &usermapped_start);
usermapped_offset = addr - (u32_t) &usermapped_start;
#define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset)
#define FIXPTR(ptr) ptr = FIXEDPTR(ptr)
#define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct)
ASSIGN(kinfo);
ASSIGN(machine);
ASSIGN(kmessages);
ASSIGN(loadinfo);
/* adjust the pointers of the functions and the struct
* itself to the user-accessible mapping
*/
minix_kerninfo.kerninfo_magic = KERNINFO_MAGIC;
minix_kerninfo.minix_feature_flags = minix_feature_flags;
minix_kerninfo_user = (vir_bytes) FIXEDPTR(&minix_kerninfo);
return OK;
}
if (index == usermapped_index) {
return OK;
}
/* if this all fails loop over the maps */
/* list over the maps and index them */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
if(phys_maps->index == index){
assert(phys_maps->cb != NULL);
/* only update the vir addr we are
going to call the callback in enable
paging
*/
phys_maps->vir = addr;
return OK;
}
phys_maps = phys_maps->next;
}
return EINVAL;
}
int arch_enable_paging(struct proc * caller)
{
kern_phys_map *phys_maps;
assert(caller->p_seg.p_ttbr);
/* load caller's page table */
switch_address_space(caller);
/* We have now switched address spaces and the mappings are
valid. We can now remap previous mappings. This is not a
good time to do printf as the initial massing is gone and
the new mapping is not in place */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
assert(phys_maps->cb != NULL);
phys_maps->cb(phys_maps->id, phys_maps->vir);
phys_maps = phys_maps->next;
}
return OK;
}
void release_address_space(struct proc *pr)
{
pr->p_seg.p_ttbr_v = NULL;
barrier();
}
/*
* Request a physical mapping
*/
int kern_req_phys_map( phys_bytes base_address, vir_bytes io_size,
int vm_flags, kern_phys_map * priv,
kern_phys_map_mapped cb, vir_bytes id)
{
/* Assign the values to the given struct and add priv
to the list */
assert(base_address != 0);
assert(io_size % ARM_PAGE_SIZE == 0);
assert(cb != NULL);
priv->addr = base_address;
priv->size = io_size;
priv->vm_flags = vm_flags;
priv->cb = cb;
priv->id = id;
priv->index = -1;
priv->next = NULL;
if (kern_phys_map_head == NULL){
/* keep a list of items this is the first one */
kern_phys_map_head = priv;
kern_phys_map_head->next = NULL;
} else {
/* insert the item head but first keep track
of the current by putting it in next */
priv->next = kern_phys_map_head;
/* replace the head */
kern_phys_map_head = priv;
}
return 0;
}
/*
* Callback implementation where the id given to the
* kern_phys_map is a pointer to the io map base address.
* this implementation will just change that base address.
* once that area is remapped.
*/
int kern_phys_map_mapped_ptr(vir_bytes id, phys_bytes address){
*((vir_bytes*)id) = address;
return 0;
}
/*
* Request a physical mapping and put the result in the given prt
* Note that ptr will only be valid once the callback happened.
*/
int kern_phys_map_ptr(
phys_bytes base_address,
vir_bytes io_size,
int vm_flags,
kern_phys_map * priv,
vir_bytes ptr)
{
return kern_req_phys_map(base_address,io_size,vm_flags,priv,kern_phys_map_mapped_ptr,ptr);
}

View File

@@ -0,0 +1,289 @@
/* This file is part of the lowest layer of the MINIX kernel. (The other part
* is "proc.c".) The lowest layer does process switching and message handling.
*
* Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
* exceptions. TSS is set so that the kernel stack is loaded. The user context is
* saved to the proc table and the handler of the event is called. Once the
* handler is done, switch_to_user() function is called to pick a new process,
* finish what needs to be done for the next process to run, sets its context
* and switch to userspace.
*/
#include "kernel/kernel.h" /* configures the kernel */
/* sections */
#include <machine/vm.h>
#include "kernel/kernel.h"
#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include <machine/asm.h>
#include <machine/interrupt.h>
#include "archconst.h"
#include "kernel/const.h"
#include "kernel/proc.h"
#include "sconst.h"
#include <machine/multiboot.h>
#include <machine/ipcconst.h>
#include <machine/cpu.h>
#include <arm/armreg.h>
#include "bsp_intr.h"
#include "arch_proto.h" /* K_STACK_SIZE */
IMPORT(svc_stack)
/*
* Adjust lr, push pc/psr when exception triggered and switch to SVC mode
* The 'lr_offset' argument holds the adjustment.
*
* When an instruction causes the ARM core to enter the exception handler
* the value of pc is stored in the link register (lr). By default on ARM
* the program counter is 3 instruction a head of the current instruction
* being executed (because of the 3 stage pipeline). Depending on where in
* the pipeline the exception happens lr will need to de adjusted to find
* the proper return address.
*/
.macro switch_to_svc lr_offset
sub lr, lr, #\lr_offset /* do the adjustment */
srsdb sp!, #PSR_SVC32_MODE /* store the saved the return */
/* address and program status */
/* register onto the kernel stack */
/* Also modify the stack pointer. */
cps #PSR_SVC32_MODE /* do the switch to SVC. */
.endm
/*
* Test if the exception/interrupt occurred in the kernel.
* Jump to 'label' argument if it occurred in the kernel.
*
* NOTE: switch_to_svc must be called first */
.macro test_int_in_kernel, label
push {r3}
ldr r3, [sp, #8] /* get spsr. */
orr r3, r3, #(PSR_F | PSR_I) /* mask interrupts on return. */
str r3, [sp, #8] /* store spsr. */
and r3, r3, #PSR_MODE /* mask the ARM mode. */
cmp r3, #PSR_USR32_MODE /* compare it to user mode. */
pop {r3}
bne \label /* In-kernel handling. */
.endm
/* Save the register context to the proc structure */
.macro save_process_ctx
add sp, sp, #8 /* We expect srsdb pushed cpsr and lr on */
/* the stack. */
ldr lr, [sp] /* lr = proc_ptr. */
stm lr, {r0-r14}^ /* store the user mode registers */
/* proc_ptr->p_reg.r0-r14 = r0-r14. */
ldr r12, [sp, #-8] /* r12 = pc stored on the stack. */
str r12, [lr, #PCREG] /* proc_ptr->p_reg.pc = r12. */
ldr r12, [sp, #-4] /* r12 = cpsr stored on the stack. */
str r12, [lr, #PSREG] /* proc_ptr->p_reg.psr = r12. */
.endm
.macro exception_handler exc_name, exc_num, lr_offset
ENTRY(\exc_name\()_entry)
switch_to_svc \lr_offset
test_int_in_kernel \exc_name\()_entry_nested
\exc_name\()entry_from_user:
save_process_ctx
ldr fp, [sp] /* save the pointer to the current process. */
add r4, fp, #PCREG /* save the exception pc (saved lr_user) */
/* r4-r9 are callee save. */
/* stop user process cycles */
mov r0, fp /* first param: caller proc ptr. */
mov fp, #0 /* for stack trace. */
bl _C_LABEL(context_stop)
/*
* push a pointer to the interrupt state pushed by the cpu and the
* vector number pushed by the vector handler just before calling
* exception_entry and call the exception handler.
*/
mov r0, #0 /* it is not a nested exception. */
mov r1, r4 /* saved lr. */
mov r2, #\exc_num /* vector number */
bl _C_LABEL(exception_handler)
b _C_LABEL(switch_to_user)
\exc_name\()_entry_nested:
push {r0-r12, lr}
mov r0, #1 /* it is a nested exception. */
add r1, sp, #56 /* saved lr */
mov r2, #\exc_num /* vector number */
bl _C_LABEL(exception_handler)
pop {r0-r12, lr}
rfeia sp!
.endm
/* Exception handlers */
exception_handler data_abort DATA_ABORT_VECTOR 8
exception_handler prefetch_abort PREFETCH_ABORT_VECTOR 4
exception_handler undefined_inst UNDEFINED_INST_VECTOR 4
ENTRY(irq_entry)
switch_to_svc 4
test_int_in_kernel irq_entry_from_kernel
irq_entry_from_user:
save_process_ctx
/* save the pointer to the current process */
ldr fp, [sp]
push {fp} /* save caller proc ptr. */
sub sp, sp, #4 /* maintain stack alignment. */
/* stop user process cycles */
mov r0, fp /* first param: caller proc ptr. */
mov fp, #0 /* for stack trace. */
bl _C_LABEL(context_stop)
/* call handler */
bl _C_LABEL(bsp_irq_handle) /* bsp_irq_handle(void) */
add sp, sp, #4
pop {fp} /* caller proc ptr. */
dsb /* data synchronization barrier. */
b _C_LABEL(switch_to_user)
irq_entry_from_kernel:
push {r0-r12, lr}
bl _C_LABEL(context_stop_idle)
/* call handler */
bl _C_LABEL(bsp_irq_handle) /* bsp_irq_handle(void). */
/* data synchronization barrier */ dsb
pop {r0-r12, lr}
rfeia sp!
/*
* supervisor call (SVC) kernel entry point
*/
ENTRY(svc_entry)
/* Store the LR and the SPSR of the current mode onto the SVC stack */
srsdb sp!, #PSR_SVC32_MODE
save_process_ctx
/* save the pointer to the current process */
ldr fp, [sp]
cmp r3, #KERVEC_INTR
beq kernel_call_entry
cmp r3, #IPCVEC_INTR
beq ipc_entry
/* return -1 to the current process as an invalid SWI was called .*/
mov r0, #-1
str r0, [fp, #REG0]
b _C_LABEL(switch_to_user)
/*
* kernel call is only from a process to kernel
*/
ENTRY(kernel_call_entry)
/*
* pass the syscall arguments from userspace to the handler.
* save_process_ctx() does not clobber these registers, they are still
* set as the userspace has set them.
*/
push {fp} /* save caller proc ptr. */
push {r0} /* save msg ptr so it's not clobbered. */
/* stop user process cycles */
mov r0, fp /* first param: caller proc ptr */
mov fp, #0 /* for stack trace */
bl _C_LABEL(context_stop)
pop {r0} /* first param: msg ptr. */
pop {r1} /* second param: caller proc ptr. */
bl _C_LABEL(kernel_call)
b _C_LABEL(switch_to_user)
/*
* IPC is only from a process to kernel
*/
ENTRY(ipc_entry)
/*
* pass the syscall arguments from userspace to the handler.
* save_process_ctx() does not clobber these registers, they are still
* set as the userspace have set them
*/
push {fp} /* save caller proc ptr. */
push {r0-r2} /* save regs so they're not clobbered. */
/* stop user process cycles */
mov r0, fp /* first param: caller proc ptr. */
mov fp, #0 /* for stack trace. */
bl _C_LABEL(context_stop)
pop {r0-r2} /* restore regs */
bl _C_LABEL(do_ipc)
/* restore the current process pointer and save the return value */
pop {fp} /* caller proc ptr. */
str r0, [fp, #REG0]
b _C_LABEL(switch_to_user)
ENTRY(invalid_svc)
b .
ENTRY(restore_user_context)
/* sp holds the proc ptr */
mov sp, r0
/* Set SPSR and LR for return */
ldr r0, [sp, #PSREG]
msr spsr_fsxc, r0 /* flags , status, extension control. */
ldr lr, [sp, #PCREG]
/* Restore user-mode registers from proc struct */
ldm sp, {r0-r14}^
ldr sp, =_C_LABEL(svc_stack)
ldr sp, [sp]
/* To user mode! */
movs pc, lr /* preferred way of returning from svc */
/*===========================================================================*/
/* data */
/*===========================================================================*/
.data
.short 0x526F /* this must be the first data entry (magic #) */
.bss
.data
.balign 4
k_initial_stack:
.space K_STACK_SIZE
LABEL(__k_unpaged_k_initial_stktop)
/*
* the kernel stack
*/
k_boot_stack:
.space K_STACK_SIZE /* kernel stack */ /* FIXME use macro here */
LABEL(k_boot_stktop) /* top of kernel stack */
.balign K_STACK_SIZE
LABEL(k_stacks_start)
/* two pages for each stack, one for data, other as a sandbox */
.space 2 * (K_STACK_SIZE * CONFIG_MAX_CPUS)
LABEL(k_stacks_end)
/* top of kernel stack */

View File

@@ -0,0 +1,317 @@
#include <minix/cpufeature.h>
#include <minix/type.h>
#include <assert.h>
#include "kernel/kernel.h"
#include "arch_proto.h"
#include <machine/cpu.h>
#include <arm/armreg.h>
#include <string.h>
#include <minix/type.h>
/* These are set/computed in kernel.lds. */
extern char _kern_vir_base, _kern_phys_base, _kern_size;
/* Retrieve the absolute values to something we can use. */
static phys_bytes kern_vir_start = (phys_bytes) &_kern_vir_base;
static phys_bytes kern_phys_start = (phys_bytes) &_kern_phys_base;
static phys_bytes kern_kernlen = (phys_bytes) &_kern_size;
/* page directory we can use to map things */
static u32_t pagedir[4096] __aligned(16384);
void print_memmap(kinfo_t *cbi)
{
int m;
assert(cbi->mmap_size < MAXMEMMAP);
for(m = 0; m < cbi->mmap_size; m++) {
phys_bytes addr = cbi->memmap[m].mm_base_addr, endit = cbi->memmap[m].mm_base_addr + cbi->memmap[m].mm_length;
printf("%08lx-%08lx ",addr, endit);
}
printf("\nsize %08lx\n", cbi->mmap_size);
}
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
{
int m;
phys_bytes o;
if((o=start % ARM_PAGE_SIZE))
start -= o;
if((o=end % ARM_PAGE_SIZE))
end += ARM_PAGE_SIZE - o;
assert(kernel_may_alloc);
for(m = 0; m < cbi->mmap_size; m++) {
phys_bytes substart = start, subend = end;
phys_bytes memaddr = cbi->memmap[m].mm_base_addr,
memend = cbi->memmap[m].mm_base_addr + cbi->memmap[m].mm_length;
/* adjust cut range to be a subset of the free memory */
if(substart < memaddr) substart = memaddr;
if(subend > memend) subend = memend;
if(substart >= subend) continue;
/* if there is any overlap, forget this one and add
* 1-2 subranges back
*/
cbi->memmap[m].mm_base_addr = cbi->memmap[m].mm_length = 0;
if(substart > memaddr)
add_memmap(cbi, memaddr, substart-memaddr);
if(subend < memend)
add_memmap(cbi, subend, memend-subend);
}
}
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
{
int m;
#define LIMIT 0xFFFFF000
/* Truncate available memory at 4GB as the rest of minix
* currently can't deal with any bigger.
*/
if(addr > LIMIT) {
return;
}
if(addr + len > LIMIT) {
len -= (addr + len - LIMIT);
}
assert(cbi->mmap_size < MAXMEMMAP);
if(len == 0) {
return;
}
addr = roundup(addr, ARM_PAGE_SIZE);
len = rounddown(len, ARM_PAGE_SIZE);
assert(kernel_may_alloc);
for(m = 0; m < MAXMEMMAP; m++) {
phys_bytes highmark;
if(cbi->memmap[m].mm_length) {
continue;
}
cbi->memmap[m].mm_base_addr = addr;
cbi->memmap[m].mm_length = len;
cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE;
if(m >= cbi->mmap_size) {
cbi->mmap_size = m+1;
}
highmark = addr + len;
if(highmark > cbi->mem_high_phys) {
cbi->mem_high_phys = highmark;
}
return;
}
panic("no available memmap slot");
}
u32_t *alloc_pagetable(phys_bytes *ph)
{
u32_t *ret;
#define PG_PAGETABLES 24
static u32_t pagetables[PG_PAGETABLES][256] __aligned(1024);
static int pt_inuse = 0;
if(pt_inuse >= PG_PAGETABLES) {
panic("no more pagetables");
}
assert(sizeof(pagetables[pt_inuse]) == 1024);
ret = pagetables[pt_inuse++];
*ph = vir2phys(ret);
return ret;
}
#define PAGE_KB (ARM_PAGE_SIZE / 1024)
phys_bytes pg_alloc_page(kinfo_t *cbi)
{
int m;
multiboot_memory_map_t *mmap;
assert(kernel_may_alloc);
for(m = 0; m < cbi->mmap_size; m++) {
mmap = &cbi->memmap[m];
if(!mmap->mm_length) {
continue;
}
assert(mmap->mm_length > 0);
assert(!(mmap->mm_length % ARM_PAGE_SIZE));
assert(!(mmap->mm_base_addr % ARM_PAGE_SIZE));
u32_t addr = mmap->mm_base_addr;
mmap->mm_base_addr += ARM_PAGE_SIZE;
mmap->mm_length -= ARM_PAGE_SIZE;
cbi->kernel_allocated_bytes_dynamic += ARM_PAGE_SIZE;
return addr;
}
panic("can't find free memory");
}
void pg_identity(kinfo_t *cbi)
{
int i;
phys_bytes phys;
/* We map memory that does not correspond to physical memory
* as non-cacheable. Make sure we know what it is.
*/
assert(cbi->mem_high_phys);
/* Set up an identity mapping page directory */
for(i = 0; i < ARM_VM_DIR_ENTRIES; i++) {
u32_t flags = ARM_VM_SECTION
| ARM_VM_SECTION_USER
| ARM_VM_SECTION_DOMAIN;
phys = i * ARM_SECTION_SIZE;
/* mark mormal memory as cacheable. TODO: fix hard coded values */
if (phys >= PHYS_MEM_BEGIN && phys <= PHYS_MEM_END) {
pagedir[i] = phys | flags | ARM_VM_SECTION_CACHED;
} else {
pagedir[i] = phys | flags | ARM_VM_SECTION_DEVICE;
}
}
}
int pg_mapkernel(void)
{
int pde;
u32_t mapped = 0, kern_phys = kern_phys_start;
assert(!(kern_vir_start % ARM_SECTION_SIZE));
assert(!(kern_phys_start % ARM_SECTION_SIZE));
pde = kern_vir_start / ARM_SECTION_SIZE; /* start pde */
while(mapped < kern_kernlen) {
pagedir[pde] = (kern_phys & ARM_VM_SECTION_MASK)
| ARM_VM_SECTION
| ARM_VM_SECTION_SUPER
| ARM_VM_SECTION_DOMAIN
| ARM_VM_SECTION_CACHED;
mapped += ARM_SECTION_SIZE;
kern_phys += ARM_SECTION_SIZE;
pde++;
}
return pde; /* free pde */
}
void vm_enable_paging(void)
{
u32_t sctlr;
u32_t actlr;
write_ttbcr(0);
/* Set all Domains to Client */
write_dacr(0x55555555);
sctlr = read_sctlr();
/* Enable MMU */
sctlr |= CPU_CONTROL_MMU_ENABLE;
/* TRE set to zero (default reset value): TEX[2:0] are used, plus C and B bits.*/
sctlr &= ~CPU_CONTROL_TR_ENABLE;
/* AFE set to zero (default reset value): not using simplified model. */
sctlr &= ~CPU_CONTROL_AF_ENABLE;
/* Enable instruction ,data cache and branch prediction */
sctlr |= CPU_CONTROL_DC_ENABLE;
sctlr |= CPU_CONTROL_IC_ENABLE;
sctlr |= CPU_CONTROL_BPRD_ENABLE;
/* Enable barriers */
sctlr |= CPU_CONTROL_32BD_ENABLE;
/* Enable L2 cache (cortex-a8) */
#define CORTEX_A8_L2EN (0x02)
actlr = read_actlr();
actlr |= CORTEX_A8_L2EN;
write_actlr(actlr);
write_sctlr(sctlr);
}
phys_bytes pg_load()
{
phys_bytes phpagedir = vir2phys(pagedir);
write_ttbr0(phpagedir);
return phpagedir;
}
void pg_clear(void)
{
memset(pagedir, 0, sizeof(pagedir));
}
phys_bytes pg_rounddown(phys_bytes b)
{
phys_bytes o;
if(!(o = b % ARM_PAGE_SIZE)) {
return b;
}
return b - o;
}
void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end,
kinfo_t *cbi)
{
static int mapped_pde = -1;
static u32_t *pt = NULL;
int pde, pte;
assert(kernel_may_alloc);
if(phys == PG_ALLOCATEME) {
assert(!(vaddr % ARM_PAGE_SIZE));
} else {
assert((vaddr % ARM_PAGE_SIZE) == (phys % ARM_PAGE_SIZE));
vaddr = pg_rounddown(vaddr);
phys = pg_rounddown(phys);
}
assert(vaddr < kern_vir_start);
while(vaddr < vaddr_end) {
phys_bytes source = phys;
assert(!(vaddr % ARM_PAGE_SIZE));
if(phys == PG_ALLOCATEME) {
source = pg_alloc_page(cbi);
} else {
assert(!(phys % ARM_PAGE_SIZE));
}
assert(!(source % ARM_PAGE_SIZE));
pde = ARM_VM_PDE(vaddr);
pte = ARM_VM_PTE(vaddr);
if(mapped_pde < pde) {
phys_bytes ph;
pt = alloc_pagetable(&ph);
pagedir[pde] = (ph & ARM_VM_PDE_MASK)
| ARM_VM_PAGEDIR
| ARM_VM_PDE_DOMAIN;
mapped_pde = pde;
}
assert(pt);
pt[pte] = (source & ARM_VM_PTE_MASK)
| ARM_VM_PAGETABLE
| ARM_VM_PTE_CACHED
| ARM_VM_PTE_USER;
vaddr += ARM_PAGE_SIZE;
if(phys != PG_ALLOCATEME) {
phys += ARM_PAGE_SIZE;
}
}
}
void pg_info(reg_t *pagedir_ph, u32_t **pagedir_v)
{
*pagedir_ph = vir2phys(pagedir);
*pagedir_v = pagedir;
}

View File

@@ -0,0 +1,397 @@
/* $NetBSD: memcpy_arm.S,v 1.4 2013/08/11 04:56:32 matt Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <machine/asm.h>
#if !defined(__minix)
#if defined(__ARM_EABI__)
STRONG_ALIAS(__aeabi_memcpy, memcpy)
#endif
#endif /* !defined(__minix) */
/*
* This is one fun bit of code ...
* Some easy listening music is suggested while trying to understand this
* code e.g. Iron Maiden
*
* For anyone attempting to understand it :
*
* The core code is implemented here with simple stubs for memcpy().
*
* All local labels are prefixed with Lmemcpy_
* Following the prefix a label starting f is used in the forward copy code
* while a label using b is used in the backwards copy code
* The source and destination addresses determine whether a forward or
* backward copy is performed.
* Separate bits of code are used to deal with the following situations
* for both the forward and backwards copy.
* unaligned source address
* unaligned destination address
* Separate copy routines are used to produce an optimised result for each
* of these cases.
* The copy code will use LDM/STM instructions to copy up to 32 bytes at
* a time where possible.
*
* Note: r12 (aka ip) can be trashed during the function along with
* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
* Additional registers are preserved prior to use i.e. r4, r5 & lr
*
* Apologies for the state of the comments ;-)
*/
/* For MINIX, we always spill r0, r4, r5, and lr, so we can easily
* clean up the stack after a phys_copy fault. NetBSD, in contrast,
* spills the minimum number of registers for each path.
*/
#if defined(__minix)
/* LINTSTUB: Func: void *phys_copy(void *src, void *dst, size_t len) */
ENTRY(phys_copy)
/* switch the source and destination registers */
eor r0, r1, r0
eor r1, r0, r1
eor r0, r1, r0
#else
/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */
ENTRY(memcpy)
#endif
/* save leaf functions having to store this away */
#if defined(__minix)
push {r0, r4, r5, lr} /* memcpy() returns dest addr */
#else
push {r0, lr} /* memcpy() returns dest addr */
#endif
subs r2, r2, #4
blt .Lmemcpy_l4 /* less than 4 bytes */
ands r12, r0, #3
bne .Lmemcpy_destul /* oh unaligned destination addr */
ands r12, r1, #3
bne .Lmemcpy_srcul /* oh unaligned source addr */
.Lmemcpy_t8:
/* We have aligned source and destination */
subs r2, r2, #8
blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */
subs r2, r2, #0x14
blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */
#if !defined(__minix)
push {r4} /* borrow r4 */
#endif
/* blat 32 bytes at a time */
/* XXX for really big copies perhaps we should use more registers */
.Lmemcpy_loop32:
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
subs r2, r2, #0x20
bge .Lmemcpy_loop32
cmn r2, #0x10
ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
stmiage r0!, {r3, r4, r12, lr}
subge r2, r2, #0x10
#if !defined(__minix)
pop {r4} /* return r4 */
#endif
.Lmemcpy_l32:
adds r2, r2, #0x14
/* blat 12 bytes at a time */
.Lmemcpy_loop12:
ldmiage r1!, {r3, r12, lr}
stmiage r0!, {r3, r12, lr}
subsge r2, r2, #0x0c
bge .Lmemcpy_loop12
.Lmemcpy_l12:
adds r2, r2, #8
blt .Lmemcpy_l4
subs r2, r2, #4
ldrlt r3, [r1], #4
strlt r3, [r0], #4
ldmiage r1!, {r3, r12}
stmiage r0!, {r3, r12}
subge r2, r2, #4
.Lmemcpy_l4:
/* less than 4 bytes to go */
adds r2, r2, #4
#if defined(__minix)
popeq {r0, r4, r5}
moveq r0, #0
popeq {pc}
#else
#ifdef __APCS_26_
ldmiaeq sp!, {r0, pc}^ /* done */
#else
popeq {r0, pc} /* done */
#endif
#endif
/* copy the crud byte at a time */
cmp r2, #2
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrbge r3, [r1], #1
strbge r3, [r0], #1
ldrbgt r3, [r1], #1
strbgt r3, [r0], #1
#if defined(__minix)
pop {r0, r4, r5}
mov r0, #0
pop {pc}
#else
pop {r0, pc}
#endif
/* erg - unaligned destination */
.Lmemcpy_destul:
rsb r12, r12, #4
cmp r12, #2
/* align destination with byte copies */
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrbge r3, [r1], #1
strbge r3, [r0], #1
ldrbgt r3, [r1], #1
strbgt r3, [r0], #1
subs r2, r2, r12
blt .Lmemcpy_l4 /* less the 4 bytes */
ands r12, r1, #3
beq .Lmemcpy_t8 /* we have an aligned source */
/* erg - unaligned source */
/* This is where it gets nasty ... */
.Lmemcpy_srcul:
bic r1, r1, #3
ldr lr, [r1], #4
cmp r12, #2
bgt .Lmemcpy_srcul3
beq .Lmemcpy_srcul2
cmp r2, #0x0c
blt .Lmemcpy_srcul1loop4
sub r2, r2, #0x0c
#if !defined(__minix)
push {r4, r5}
#endif
.Lmemcpy_srcul1loop16:
#ifdef __ARMEB__
mov r3, lr, lsl #8
#else
mov r3, lr, lsr #8
#endif
ldmia r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr r3, r3, r4, lsr #24
mov r4, r4, lsl #8
orr r4, r4, r5, lsr #24
mov r5, r5, lsl #8
orr r5, r5, r12, lsr #24
mov r12, r12, lsl #8
orr r12, r12, lr, lsr #24
#else
orr r3, r3, r4, lsl #24
mov r4, r4, lsr #8
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r12, lsl #24
mov r12, r12, lsr #8
orr r12, r12, lr, lsl #24
#endif
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul1loop16
#if !defined(__minix)
pop {r4, r5}
#endif
adds r2, r2, #0x0c
blt .Lmemcpy_srcul1l4
.Lmemcpy_srcul1loop4:
#ifdef __ARMEB__
mov r12, lr, lsl #8
#else
mov r12, lr, lsr #8
#endif
ldr lr, [r1], #4
#ifdef __ARMEB__
orr r12, r12, lr, lsr #24
#else
orr r12, r12, lr, lsl #24
#endif
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul1loop4
.Lmemcpy_srcul1l4:
sub r1, r1, #3
b .Lmemcpy_l4
.Lmemcpy_srcul2:
cmp r2, #0x0c
blt .Lmemcpy_srcul2loop4
sub r2, r2, #0x0c
#if !defined(__minix)
push {r4, r5}
#endif
.Lmemcpy_srcul2loop16:
#ifdef __ARMEB__
mov r3, lr, lsl #16
#else
mov r3, lr, lsr #16
#endif
ldmia r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr r3, r3, r4, lsr #16
mov r4, r4, lsl #16
orr r4, r4, r5, lsr #16
mov r5, r5, lsl #16
orr r5, r5, r12, lsr #16
mov r12, r12, lsl #16
orr r12, r12, lr, lsr #16
#else
orr r3, r3, r4, lsl #16
mov r4, r4, lsr #16
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r12, lsl #16
mov r12, r12, lsr #16
orr r12, r12, lr, lsl #16
#endif
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul2loop16
#if !defined(__minix)
pop {r4, r5}
#endif
adds r2, r2, #0x0c
blt .Lmemcpy_srcul2l4
.Lmemcpy_srcul2loop4:
#ifdef __ARMEB__
mov r12, lr, lsl #16
#else
mov r12, lr, lsr #16
#endif
ldr lr, [r1], #4
#ifdef __ARMEB__
orr r12, r12, lr, lsr #16
#else
orr r12, r12, lr, lsl #16
#endif
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul2loop4
.Lmemcpy_srcul2l4:
sub r1, r1, #2
b .Lmemcpy_l4
.Lmemcpy_srcul3:
cmp r2, #0x0c
blt .Lmemcpy_srcul3loop4
sub r2, r2, #0x0c
#if !defined(__minix)
push {r4, r5}
#endif
.Lmemcpy_srcul3loop16:
#ifdef __ARMEB__
mov r3, lr, lsl #24
#else
mov r3, lr, lsr #24
#endif
ldmia r1!, {r4, r5, r12, lr}
#ifdef __ARMEB__
orr r3, r3, r4, lsr #8
mov r4, r4, lsl #24
orr r4, r4, r5, lsr #8
mov r5, r5, lsl #24
orr r5, r5, r12, lsr #8
mov r12, r12, lsl #24
orr r12, r12, lr, lsr #8
#else
orr r3, r3, r4, lsl #8
mov r4, r4, lsr #24
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r12, lsl #8
mov r12, r12, lsr #24
orr r12, r12, lr, lsl #8
#endif
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul3loop16
#if !defined(__minix)
pop {r4, r5}
#endif
adds r2, r2, #0x0c
blt .Lmemcpy_srcul3l4
.Lmemcpy_srcul3loop4:
#ifdef __ARMEB__
mov r12, lr, lsl #24
#else
mov r12, lr, lsr #24
#endif
ldr lr, [r1], #4
#ifdef __ARMEB__
orr r12, r12, lr, lsr #8
#else
orr r12, r12, lr, lsl #8
#endif
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul3loop4
.Lmemcpy_srcul3l4:
sub r1, r1, #1
b .Lmemcpy_l4
#if defined(__minix)
LABEL(phys_copy_fault) /* kernel can send us here */
pop {r0, r4, r5}
pop {pc}
LABEL(phys_copy_fault_in_kernel) /* kernel can send us here */
pop {r0, r4, r5}
mrc p15, 0, r0, c6, c0, 0 /* Read DFAR */
pop {pc}
#else
END(memcpy)
#endif

View File

@@ -0,0 +1,274 @@
/* $NetBSD: memset.S,v 1.1 2005/12/20 19:28:49 christos Exp $ */
/*
* Copyright 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1995 Mark Brinicombe.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe.
* 4. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <machine/asm.h>
/*
* memset: Sets a block of memory to the specified value
*
* On entry:
* r0 - dest address
* r1 - byte to write
* r2 - number of bytes to write
*
* On exit:
* r0 - dest address
*/
#ifdef _BZERO
/* LINTSTUB: Func: void bzero(void *, size_t) */
ENTRY(bzero)
mov r3, #0x00
#else
#if defined(__minix)
/* LINTSTUB: Func: void *phys_memset(void *, int, size_t) */
ENTRY(phys_memset)
#else
/* LINTSTUB: Func: void *memset(void *, int, size_t) */
ENTRY(memset)
#endif
and r3, r1, #0xff /* We deal with bytes */
mov r1, r2
#endif
cmp r1, #0x04 /* Do we have less than 4 bytes */
mov ip, r0
blt .Lmemset_lessthanfour
/* Ok first we will word align the address */
ands r2, ip, #0x03 /* Get the bottom two bits */
bne .Lmemset_wordunaligned /* The address is not word aligned */
/* We are now word aligned */
.Lmemset_wordaligned:
#ifndef _BZERO
orr r3, r3, r3, lsl #8 /* Extend value to 16-bits */
#endif
#ifdef __XSCALE__
tst ip, #0x04 /* Quad-align for Xscale */
#else
cmp r1, #0x10
#endif
#ifndef _BZERO
orr r3, r3, r3, lsl #16 /* Extend value to 32-bits */
#endif
#ifdef __XSCALE__
subne r1, r1, #0x04 /* Quad-align if necessary */
strne r3, [ip], #0x04
cmp r1, #0x10
#endif
blt .Lmemset_loop4 /* If less than 16 then use words */
mov r2, r3 /* Duplicate data */
cmp r1, #0x80 /* If < 128 then skip the big loop */
blt .Lmemset_loop32
/* Do 128 bytes at a time */
.Lmemset_loop128:
subs r1, r1, #0x80
#ifdef __XSCALE__
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
#else
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
#endif
bgt .Lmemset_loop128
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq) /* Zero length so just exit */
add r1, r1, #0x80 /* Adjust for extra sub */
/* Do 32 bytes at a time */
.Lmemset_loop32:
subs r1, r1, #0x20
#ifdef __XSCALE__
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
strged r2, [ip], #0x08
#else
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
#endif
bgt .Lmemset_loop32
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq) /* Zero length so just exit */
adds r1, r1, #0x10 /* Partially adjust for extra sub */
/* Deal with 16 bytes or more */
#ifdef __XSCALE__
strged r2, [ip], #0x08
strged r2, [ip], #0x08
#else
stmgeia ip!, {r2-r3}
stmgeia ip!, {r2-r3}
#endif
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq) /* Zero length so just exit */
addlt r1, r1, #0x10 /* Possibly adjust for extra sub */
/* We have at least 4 bytes so copy as words */
.Lmemset_loop4:
subs r1, r1, #0x04
strge r3, [ip], #0x04
bgt .Lmemset_loop4
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq) /* Zero length so just exit */
#ifdef __XSCALE__
/* Compensate for 64-bit alignment check */
adds r1, r1, #0x04
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq)
cmp r1, #2
#else
cmp r1, #-2
#endif
strb r3, [ip], #0x01 /* Set 1 byte */
strgeb r3, [ip], #0x01 /* Set another byte */
strgtb r3, [ip] /* and a third */
#if defined(__minix)
mov r0, #0
#endif
RET /* Exit */
.Lmemset_wordunaligned:
rsb r2, r2, #0x004
strb r3, [ip], #0x01 /* Set 1 byte */
cmp r2, #0x02
strgeb r3, [ip], #0x01 /* Set another byte */
sub r1, r1, r2
strgtb r3, [ip], #0x01 /* and a third */
cmp r1, #0x04 /* More than 4 bytes left? */
bge .Lmemset_wordaligned /* Yup */
.Lmemset_lessthanfour:
cmp r1, #0x00
#if defined(__minix)
moveq r0, #0
#endif
RETc(eq) /* Zero length so exit */
strb r3, [ip], #0x01 /* Set 1 byte */
cmp r1, #0x02
strgeb r3, [ip], #0x01 /* Set another byte */
strgtb r3, [ip] /* and a third */
#if defined(__minix)
mov r0, #0
#endif
RET /* Exit */
#if defined(__minix)
LABEL(memset_fault) /* kernel can send us here */
mov r0, #0
RET
LABEL(memset_fault_in_kernel) /* kernel can send us here */
mrc p15, 0, r0, c6, c0, 0 /* Read DFAR */
RET
#endif

View File

@@ -0,0 +1,426 @@
#define UNPAGED 1 /* for proper kmain() prototype */
#include "kernel/kernel.h"
#include <assert.h>
#include <stdlib.h>
#include <minix/minlib.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/board.h>
#include <minix/com.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/reboot.h>
#include "string.h"
#include "arch_proto.h"
#include "direct_utils.h"
#include "bsp_serial.h"
#include "glo.h"
#include <machine/multiboot.h>
#if USE_SYSDEBUG
#define MULTIBOOT_VERBOSE 1
#endif
/* to-be-built kinfo struct, diagnostics buffer */
kinfo_t kinfo;
struct kmessages kmessages;
/* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
static void setup_mbi(multiboot_info_t *mbi, char *bootargs);
/* String length used for mb_itoa */
#define ITOA_BUFFER_SIZE 20
/* Kernel may use memory */
int kernel_may_alloc = 1;
/* kernel bss */
extern u32_t _edata;
extern u32_t _end;
/* kernel unpaged bss */
extern char _kern_unpaged_edata;
extern char _kern_unpaged_end;
/**
*
* The following function combines a few things together
* that can well be done using standard libc like strlen/strstr
* and such but these are not available in pre_init stage.
*
* The function expects content to be in the form of space separated
* key value pairs.
* param content the contents to search in
* param key the key to find (this *should* include the key/value delimiter)
* param value a pointer to an initialized char * of at least value_max_len length
* param value_max_len the maximum length of the value to store in value including
* the end char
*
**/
int find_value(char * content,char * key,char *value,int value_max_len){
char *iter,*keyp;
int key_len,content_len,match_len,value_len;
/* return if the input is invalid */
if (key == NULL || content == NULL || value == NULL) {
return 1;
}
/* find the key and content length */
key_len = content_len =0;
for(iter = key ; *iter != '\0'; iter++, key_len++);
for(iter = content ; *iter != '\0'; iter++, content_len++);
/* return if key or content length invalid */
if (key_len == 0 || content_len == 0) {
return 1;
}
/* now find the key in the contents */
match_len =0;
for (iter = content ,keyp=key; match_len < key_len && *iter != '\0' ; iter++) {
if (*iter == *keyp) {
match_len++;
keyp++;
continue;
}
/* The current key does not match the value , reset */
match_len =0;
keyp=key;
}
if (match_len == key_len) {
printf("key found at %d %s\n", match_len, &content[match_len]);
value_len = 0;
/* copy the content to the value char iter already points to the first
char value */
while(*iter != '\0' && *iter != ' ' && value_len + 1< value_max_len) {
*value++ = *iter++;
value_len++;
}
*value='\0';
return 0;
}
return 1; /* not found */
}
static int mb_set_param(char *bigbuf,char *name,char *value, kinfo_t *cbi)
{
/* bigbuf contains a list of key=value pairs separated by \0 char.
* The list itself is ended by a second \0 terminator*/
char *p = bigbuf;
char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
char *q;
int namelen = strlen(name);
int valuelen = strlen(value);
/* Some variables we recognize */
if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; }
if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); }
/* Delete the item if already exists */
while (*p) {
if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
q = p;
/* let q point to the end of the entry */
while (*q) q++;
/* now copy the remained of the buffer */
for (q++; q < bufend; q++, p++)
*p = *q;
break;
}
/* find the end of the buffer */
while (*p++);
p++;
}
/* find the first empty spot */
for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++);
/* unless we are the first entry step over the delimiter */
if (p > bigbuf) p++;
/* Make sure there's enough space for the new parameter */
if (p + namelen + valuelen + 3 > bufend) {
return -1;
}
strcpy(p, name);
p[namelen] = '=';
strcpy(p + namelen + 1, value);
p[namelen + valuelen + 1] = 0;
p[namelen + valuelen + 2] = 0; /* end with a second delimiter */
return 0;
}
int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
{
multiboot_module_t *cmp = &mod[cmp_mod];
int m;
#define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end)
#define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
INRANGE(mod1, mod2->mod_end))
for(m = 0; m < n; m++) {
multiboot_module_t *thismod = &mod[m];
if(m == cmp_mod) continue;
if(OVERLAP(thismod, cmp)) {
return 1;
}
}
return 0;
}
/* XXX: hard-coded stuff for modules */
#define MB_MODS_NR NR_BOOT_MODULES
#define MB_MODS_BASE 0x82000000
#define MB_MODS_ALIGN 0x00800000 /* 8 MB */
#define MB_MMAP_START 0x80000000
#define MB_MMAP_SIZE 0x10000000 /* 256 MB */
multiboot_module_t mb_modlist[MB_MODS_NR];
multiboot_memory_map_t mb_memmap;
void setup_mbi(multiboot_info_t *mbi, char *bootargs)
{
memset(mbi, 0, sizeof(*mbi));
mbi->flags = MULTIBOOT_INFO_MODS | MULTIBOOT_INFO_MEM_MAP |
MULTIBOOT_INFO_CMDLINE;
mbi->mi_mods_count = MB_MODS_NR;
mbi->mods_addr = (u32_t)&mb_modlist;
int i;
for (i = 0; i < MB_MODS_NR; ++i) {
mb_modlist[i].mod_start = MB_MODS_BASE + i * MB_MODS_ALIGN;
mb_modlist[i].mod_end = mb_modlist[i].mod_start + MB_MODS_ALIGN
- ARM_PAGE_SIZE;
mb_modlist[i].cmdline = 0;
}
/* morph the bootargs into multiboot */
mbi->cmdline = (u32_t) bootargs;
mbi->mmap_addr =(u32_t)&mb_memmap;
mbi->mmap_length = sizeof(mb_memmap);
mb_memmap.size = sizeof(multiboot_memory_map_t);
mb_memmap.mm_base_addr = MB_MMAP_START;
mb_memmap.mm_length = MB_MMAP_SIZE;
mb_memmap.type = MULTIBOOT_MEMORY_AVAILABLE;
}
void get_parameters(kinfo_t *cbi, char *bootargs)
{
multiboot_memory_map_t *mmap;
multiboot_info_t *mbi = &cbi->mbi;
int var_i,value_i, m, k;
char *p;
extern char _kern_phys_base, _kern_vir_base, _kern_size,
_kern_unpaged_start, _kern_unpaged_end;
phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
kernsize = (phys_bytes) &_kern_size;
#define BUF 1024
static char cmdline[BUF];
/* get our own copy of the multiboot info struct and module list */
setup_mbi(mbi, bootargs);
/* Set various bits of info for the higher-level kernel. */
cbi->mem_high_phys = 0;
cbi->user_sp = (vir_bytes) &_kern_vir_base;
cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
cbi->bootstrap_start;
cbi->kmess = &kmess;
/* set some configurable defaults */
cbi->do_serial_debug = 1;
cbi->serial_debug_baud = 115200;
/* parse boot command line */
if (mbi->flags&MULTIBOOT_INFO_CMDLINE) {
static char var[BUF];
static char value[BUF];
/* Override values with cmdline argument */
memcpy(cmdline, (void *) mbi->cmdline, BUF);
p = cmdline;
while (*p) {
var_i = 0;
value_i = 0;
while (*p == ' ') p++; /* skip spaces */
if (!*p) break; /* is this the end? */
while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
var[var_i++] = *p++ ;
var[var_i] = 0;
if (*p++ != '=') continue; /* skip if not name=value */
while (*p && *p != ' ' && value_i < BUF - 1) {
value[value_i++] = *p++ ;
}
value[value_i] = 0;
mb_set_param(cbi->param_buf, var, value, cbi);
}
}
/* let higher levels know what we are booting on */
mb_set_param(cbi->param_buf, ARCHVARNAME, (char *)get_board_arch_name(machine.board_id), cbi);
mb_set_param(cbi->param_buf, BOARDVARNAME,(char *)get_board_name(machine.board_id) , cbi);
/* round user stack down to leave a gap to catch kernel
* stack overflow; and to distinguish kernel and user addresses
* at a glance (0xf.. vs 0xe..)
*/
cbi->user_sp &= 0xF0000000;
cbi->user_end = cbi->user_sp;
/* kernel bytes without bootstrap code/data that is currently
* still needed but will be freed after bootstrapping.
*/
kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
kinfo.kernel_allocated_bytes -= cbi->bootstrap_len;
assert(!(cbi->bootstrap_start % ARM_PAGE_SIZE));
cbi->bootstrap_len = rounddown(cbi->bootstrap_len, ARM_PAGE_SIZE);
assert(mbi->flags & MULTIBOOT_INFO_MODS);
assert(mbi->mi_mods_count < MULTIBOOT_MAX_MODS);
assert(mbi->mi_mods_count > 0);
memcpy(&cbi->module_list, (void *) mbi->mods_addr,
mbi->mi_mods_count * sizeof(multiboot_module_t));
memset(cbi->memmap, 0, sizeof(cbi->memmap));
/* mem_map has a variable layout */
if(mbi->flags & MULTIBOOT_INFO_MEM_MAP) {
cbi->mmap_size = 0;
for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
(unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
mmap = (multiboot_memory_map_t *)
((unsigned long) mmap + mmap->size + sizeof(mmap->size))) {
if(mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
add_memmap(cbi, mmap->mm_base_addr, mmap->mm_length);
}
} else {
assert(mbi->flags & MULTIBOOT_INFO_MEMORY);
add_memmap(cbi, 0, mbi->mem_lower_unused*1024);
add_memmap(cbi, 0x100000, mbi->mem_upper_unused*1024);
}
/* Sanity check: the kernel nor any of the modules may overlap
* with each other. Pretend the kernel is an extra module for a
* second.
*/
k = mbi->mi_mods_count;
assert(k < MULTIBOOT_MAX_MODS);
cbi->module_list[k].mod_start = kernbase;
cbi->module_list[k].mod_end = kernbase + kernsize;
cbi->mods_with_kernel = mbi->mi_mods_count+1;
cbi->kern_mod = k;
for(m = 0; m < cbi->mods_with_kernel; m++) {
#if 0
printf("checking overlap of module %08lx-%08lx\n",
cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
#endif
if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
panic("overlapping boot modules/kernel");
/* We cut out the bits of memory that we know are
* occupied by the kernel and boot modules.
*/
cut_memmap(cbi,
cbi->module_list[m].mod_start,
cbi->module_list[m].mod_end);
}
}
/*
* During low level init many things are not supposed to work
* serial being one of them. We therefore can't rely on the
* serial to debug. POORMANS_FAILURE_NOTIFICATION can be used
* before we setup our own vector table and will result in calling
* the bootloader's debugging methods that will hopefully show some
* information like the currnet PC at on the serial.
*/
#define POORMANS_FAILURE_NOTIFICATION asm volatile("svc #00\n")
/* use the passed cmdline argument to determine the machine id */
void set_machine_id(char *cmdline)
{
char boardname[20];
memset(boardname,'\0',20);
if (find_value(cmdline,"board_name=",boardname,20)){
/* we expect the bootloader to pass a board_name as argument
* this however did not happen and given we still are in early
* boot we can't use the serial. We therefore generate an interrupt
* and hope the bootloader will do something nice with it */
POORMANS_FAILURE_NOTIFICATION;
}
machine.board_id = get_board_id_by_short_name(boardname);
if (machine.board_id ==0){
/* same thing as above there is no safe escape */
POORMANS_FAILURE_NOTIFICATION;
}
}
kinfo_t *pre_init(int argc, char **argv)
{
char *bootargs;
/* This is the main "c" entry point into the kernel. It gets called
from head.S */
/* Clear BSS */
memset(&_edata, 0, (u32_t)&_end - (u32_t)&_edata);
memset(&_kern_unpaged_edata, 0, (u32_t)&_kern_unpaged_end - (u32_t)&_kern_unpaged_edata);
/* we get called in a c like fashion where the first arg
* is the program name (load address) and the rest are
* arguments. by convention the second argument is the
* command line */
if (argc != 2) {
POORMANS_FAILURE_NOTIFICATION;
}
bootargs = argv[1];
set_machine_id(bootargs);
bsp_ser_init();
/* Get our own copy boot params pointed to by ebx.
* Here we find out whether we should do serial output.
*/
get_parameters(&kinfo, bootargs);
/* Make and load a pagetable that will map the kernel
* to where it should be; but first a 1:1 mapping so
* this code stays where it should be.
*/
dcache_clean(); /* clean the caches */
pg_clear();
pg_identity(&kinfo);
kinfo.freepde_start = pg_mapkernel();
pg_load();
vm_enable_paging();
/* Done, return boot info so it can be passed to kmain(). */
return &kinfo;
}
/* pre_init gets executed at the memory location where the kernel was loaded by the boot loader.
* at that stage we only have a minimum set of functionality present (all symbols gets renamed to
* ensure this). The following methods are used in that context. Once we jump to kmain they are no
* longer used and the "real" implementations are visible
*/
void send_diag_sig(void) { }
void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
void busy_delay_ms(int x) { }
int raise(int n) { panic("raise(%d)\n", n); }
int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, int vm_flags,
struct kern_phys_map * priv, vir_bytes ptr) {};
struct machine machine; /* pre init stage machine */

View File

@@ -0,0 +1,24 @@
include "kernel/kernel.h"
include "kernel/proc.h"
struct proc
member REG0 p_reg.retreg
member REG1 p_reg.r1
member REG2 p_reg.r2
member REG3 p_reg.r3
member REG4 p_reg.r4
member REG5 p_reg.r5
member REG6 p_reg.r6
member REG7 p_reg.r7
member REG8 p_reg.r8
member REG9 p_reg.r9
member REG10 p_reg.r10
member FPREG p_reg.fp
member REG12 p_reg.r12
member SPREG p_reg.sp
member LRREG p_reg.lr
member PCREG p_reg.pc
member PSREG p_reg.psr
member P_TTBR p_seg.p_ttbr

View File

@@ -0,0 +1,183 @@
/* This file contains code for initialization of protected mode, to initialize
* code and data segment descriptors, and to initialize global descriptors
* for local descriptors in the process table.
*/
#include <assert.h>
#include <string.h>
#include <machine/multiboot.h>
#include "kernel/kernel.h"
#include "archconst.h"
#include "arch_proto.h"
#include <sys/exec.h>
#include <libexec.h>
struct tss_s tss[CONFIG_MAX_CPUS];
extern int exc_vector_table;
int prot_init_done = 0;
phys_bytes vir2phys(void *vir)
{
/* defined in kernel.lds */
extern char _kern_vir_base, _kern_phys_base;
u32_t offset = (vir_bytes) &_kern_vir_base -
(vir_bytes) &_kern_phys_base;
return (phys_bytes)vir - offset;
}
int tss_init(unsigned cpu, void * kernel_stack)
{
struct tss_s * t = &tss[cpu];
/*
* make space for process pointer and cpu id and point to the first
* usable word
*/
t->sp0 = ((unsigned) kernel_stack) - ARM_STACK_TOP_RESERVED;
/*
* set the cpu id at the top of the stack so we know on which cpu is
* this stak in use when we trap to kernel
*/
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
return 0;
}
multiboot_module_t *bootmod(int pnr)
{
int i;
assert(pnr >= 0);
/* Search for desired process in boot process
* list. The first NR_TASKS ones do not correspond
* to a module, however, so we don't search those.
*/
for(i = NR_TASKS; i < NR_BOOT_PROCS; i++) {
int p;
p = i - NR_TASKS;
if(image[i].proc_nr == pnr) {
assert(p < MULTIBOOT_MAX_MODS);
assert(p < kinfo.mbi.mi_mods_count);
return &kinfo.module_list[p];
}
}
panic("boot module %d not found", pnr);
}
int booting_cpu = 0;
void prot_init()
{
/* tell the HW where we stored our vector table */
write_vbar((reg_t)&exc_vector_table);
/* Set up a new post-relocate bootstrap pagetable so that
* we can map in VM, and we no longer rely on pre-relocated
* data.
*/
pg_clear();
pg_identity(&kinfo); /* Still need 1:1 for device memory . */
pg_mapkernel();
pg_load();
prot_init_done = 1;
}
static int alloc_for_vm = 0;
void arch_post_init(void)
{
/* Let memory mapping code know what's going on at bootstrap time */
struct proc *vm;
vm = proc_addr(VM_PROC_NR);
get_cpulocal_var(ptproc) = vm;
pg_info(&vm->p_seg.p_ttbr, &vm->p_seg.p_ttbr_v);
}
static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len)
{
pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
pg_load();
memset((char *) vaddr, 0, len);
alloc_for_vm += len;
return OK;
}
void arch_boot_proc(struct boot_image *ip, struct proc *rp)
{
multiboot_module_t *mod;
struct ps_strings *psp;
char *sp;
if(rp->p_nr < 0) return;
mod = bootmod(rp->p_nr);
/* Important special case: we put VM in the bootstrap pagetable
* so it can run.
*/
if(rp->p_nr == VM_PROC_NR) {
struct exec_info execi;
memset(&execi, 0, sizeof(execi));
/* exec parameters */
execi.stack_high = kinfo.user_sp;
execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */
execi.proc_e = ip->endpoint;
execi.hdr = (char *) mod->mod_start; /* phys mem direct */
execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start;
strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname));
execi.frame_len = 0;
/* callbacks for use in the kernel */
execi.copymem = libexec_copy_memcpy;
execi.clearmem = libexec_clear_memset;
execi.allocmem_prealloc_junk = libexec_pg_alloc;
execi.allocmem_prealloc_cleared = libexec_pg_alloc;
execi.allocmem_ondemand = libexec_pg_alloc;
execi.clearproc = NULL;
/* parse VM ELF binary and alloc/map it into bootstrap pagetable */
if(libexec_load_elf(&execi) != OK)
panic("VM loading failed");
/* Setup a ps_strings struct on the stack, pointing to the
* following argv, envp. */
sp = (char *)execi.stack_high;
sp -= sizeof(struct ps_strings);
psp = (struct ps_strings *) sp;
/* Take the stack pointer down three words to give startup code
* something to use as "argc", "argv" and "envp".
*/
sp -= (sizeof(void *) + sizeof(void *) + sizeof(int));
// linear address space, so it is available.
psp->ps_argvstr = (char **)(sp + sizeof(int));
psp->ps_nargvstr = 0;
psp->ps_envstr = psp->ps_argvstr + sizeof(void *);
psp->ps_nenvstr = 0;
arch_proc_init(rp, execi.pc, (vir_bytes)sp,
execi.stack_high - sizeof(struct ps_strings),
ip->proc_name);
/* Free VM blob that was just copied into existence. */
add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start);
mod->mod_end = mod->mod_start = 0;
/* Remember them */
kinfo.vm_allocated_bytes = alloc_for_vm;
}
}

View File

@@ -0,0 +1,7 @@
#ifndef __SCONST_H__
#define __SCONST_H__
#include "kernel/const.h"
#include "kernel/procoffsets.h"
#endif /* __SCONST_H__ */

View File

@@ -0,0 +1,7 @@
#ifndef _KERN_TIMER_H
#define _KERN_TIMER_H
#include "omap_timer.h"
#endif

View File

@@ -39,7 +39,7 @@ SUBDIR+= libvboxfs
SUBDIR+= libvirtio
.endif
.if (${MACHINE_ARCH} == "earm")
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
SUBDIR+= libclkconf
SUBDIR+= libgpio
SUBDIR+= libi2cdriver

View File

@@ -0,0 +1,99 @@
########################################################################
#
# Shared libc with userspace (/common/lib/libc)
#
.for f in \
memchr.o
${f}: ${LIBCOMMONCDIR}/string/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
.for f in \
byte_swap_2.o byte_swap_4.o divsi3.o divide.o udivsi3.o
${f}: ${LIBCOMMONCARCHDIR}/gen/${f:C/\.o/.S/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
CPPFLAGS.byte_swap_4.S+= -D_STANDALONE
.for f in \
__aeabi_idiv0.o __aeabi_ldiv0.o
${f}: ${LIBCOMMONCARCHDIR}/gen/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
CPPFLAGS.__aeabi_idiv0.c+= -D_STANDALONE
CPPFLAGS.__aeabi_ldiv0.c+= -D_STANDALONE
.for f in \
__aeabi_ldivmod.o __aeabi_uldivmod.o
${f}: ${LIBCOMMONCARCHDIR}/quad/${f:C/\.o/.S/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
.for f in \
memcmp.o memcpy.o memmove.o memset.o \
strcat.o strchr.o strcmp.o strcpy.o strlcpy.o strlen.o strncpy.o \
strncmp.o strrchr.o strcpy_arm.o
${f}: ${LIBCOMMONCARCHDIR}/string/${f:C/\.o/.S/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
CPPFLAGS.strcpy_arm.S+= -DSTRLCPY -D_LIBC
########################################################################
#
# Functions imported directly from libc.
#
.for f in \
alloca.o
${f}: ${LIBCARCHDIR}/gen/${f:C/\.o/.S/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
.for f in \
__aeabi_dcmpeq.o __aeabi_fcmpeq.o \
__aeabi_dcmpge.o __aeabi_fcmpge.o \
__aeabi_dcmpgt.o __aeabi_fcmpgt.o \
__aeabi_dcmple.o __aeabi_fcmple.o \
__aeabi_dcmplt.o __aeabi_fcmplt.o \
__aeabi_dcmpun.o __aeabi_fcmpun.o
CPPFLAGS.${f:C/\.o/.c/}+= -I${LIBCARCHDIR}/softfloat -I${LIBCDIR}/softfloat
CPPFLAGS.${f:C/\.o/.c/}+= -DSOFTFLOAT_FOR_GCC
${f}: ${LIBCARCHDIR}/softfloat/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
.for f in \
fpgetround.o fpsetround.o fpgetmask.o fpsetmask.o \
fpgetsticky.o fpsetsticky.o
CPPFLAGS.${f:C/\.o/.c/}+= -I${LIBCARCHDIR}/softfloat -I${LIBCDIR}/softfloat
CPPFLAGS.${f:C/\.o/.c/}+= -DSOFTFLOAT_FOR_GCC
${f}: ${LIBCDIR}/softfloat/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
SOFTFLOAT_BITS?=64
.for f in \
softfloat.o
CPPFLAGS.${f:C/\.o/.c/}+= -I${LIBCARCHDIR}/softfloat -I${LIBCDIR}/softfloat
CPPFLAGS.${f:C/\.o/.c/}+= -DSOFTFLOAT_FOR_GCC
${f}: ${LIBCDIR}/softfloat/bits${SOFTFLOAT_BITS}/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
.endfor
.if defined(HAVE_GCC) && ${HAVE_GCC} >= 45
.if (${MACHINE_CPU} == "arm")
COPTS.softfloat.c+= -Wno-enum-compare -fno-tree-vrp
.endif
.endif

View File

@@ -0,0 +1,15 @@
# Makefile for arch-dependent libsys code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS+= \
frclock_util.c \
spin.c \
tsc_util.c
CPPFLAGS+= -I${HERE}/../../
CPPFLAGS+= -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/kernel/arch/${MACHINE_ARCH}/

View File

@@ -0,0 +1,92 @@
/* Some utility functions around the free running clock on ARM. The clock is
* 32-bits wide, but we provide 64-bit wrapper functions to make it look
* similar to the read_tsc functions. On hardware we could actually make use
* of the timer overflow counter, but emulator doesn't emulate it. */
#include <minix/minlib.h>
#include <minix/sysutil.h>
#include <minix/type.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <assert.h>
#define MICROHZ 1000000ULL /* number of micros per second */
#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
static u64_t Hz;
extern struct minix_kerninfo *_minix_kerninfo;
int
micro_delay(u32_t micros)
{
u64_t start, delta, delta_end;
Hz = sys_hz();
/* Start of delay. */
read_frclock_64(&start);
assert(_minix_kerninfo->minix_arm_frclock_hz);
delta_end = (_minix_kerninfo->minix_arm_frclock_hz * micros) / MICROHZ;
/* If we have to wait for at least one HZ tick, use the regular
* tickdelay first. Round downwards on purpose, so the average
* half-tick we wait short (depending on where in the current tick
* we call tickdelay). We can correct for both overhead of tickdelay
* itself and the short wait in the busywait later.
*/
if (micros >= MICROSPERTICK(Hz))
tickdelay(micros*Hz/MICROHZ);
/* Wait (the rest) of the delay time using busywait. */
do {
read_frclock_64(&delta);
} while (delta_frclock_64(start, delta) < delta_end);
return 0;
}
u32_t frclock_64_to_micros(u64_t tsc)
{
return (u32_t) (tsc / (_minix_kerninfo->minix_arm_frclock_hz / MICROHZ));
}
void
read_frclock(u32_t *frclk)
{
assert(frclk);
assert(_minix_kerninfo->minix_frclock_tcrr);
assert(_minix_kerninfo->minix_arm_frclock_hz);
*frclk = *(volatile u32_t *)((u8_t *) _minix_kerninfo->minix_frclock_tcrr);
}
u32_t
delta_frclock(u32_t base, u32_t cur)
{
u32_t delta;
if (cur < base) {
/* We have wrapped around, so delta is base to wrapping point
* plus starting point (0) to cur. This supports wrapping once
* only. */
delta = (UINT_MAX - base) + cur;
} else {
delta = cur - base;
}
return delta;
}
void
read_frclock_64(u64_t *frclk)
{
read_frclock((u32_t *) frclk);
}
u64_t
delta_frclock_64(u64_t base, u64_t cur)
{
return (u64_t) delta_frclock((u32_t) base, (u32_t) cur);
}

View File

@@ -0,0 +1,98 @@
/* Helper functions that allow driver writers to easily busy-wait (spin) for a
* condition to become satisfied within a certain maximum time span.
*/
/* This implementation first spins without making any system calls for a
* while, and then starts using system calls (specifically, the system call to
* obtain the current time) while spinning. The reason for this is that in
* many cases, the condition to be checked will become satisfied rather
* quickly, and we want to avoid getting descheduled in that case. However,
* after a while, running out of scheduling quantum will cause our priority to
* be lowered, and we can avoid this by voluntarily giving up the CPU, by
* making a system call.
*/
#include "sysutil.h"
#include <minix/spin.h>
#include <minix/minlib.h>
/* Number of microseconds to keep spinning initially, without performing a
* system call. We pick a value somewhat smaller than a typical clock tick.
* Note that for the above reasons, we want to avoid using sys_hz() here.
*/
#define TSC_SPIN 1000 /* in microseconds */
/* Internal spin states. */
enum {
STATE_INIT, /* simply check the condition (once) */
STATE_BASE_TS, /* get the initial TSC value (once) */
STATE_TS, /* use the TSC to spin (up to TSC_SPIN us) */
STATE_UPTIME /* use the clock to spin */
};
void spin_init(spin_t *s, u32_t usecs)
{
/* Initialize the given spin state structure, set to spin at most the
* given number of microseconds.
*/
s->s_state = STATE_INIT;
s->s_usecs = usecs;
s->s_timeout = FALSE;
}
int spin_check(spin_t *s)
{
/* Check whether a timeout has taken place. Return TRUE if the caller
* should continue spinning, and FALSE if a timeout has occurred. The
* implementation assumes that it is okay to spin a little bit too long
* (up to a full clock tick extra).
*/
u64_t cur_tsc, tsc_delta;
clock_t now, micro_delta;
switch (s->s_state) {
case STATE_INIT:
s->s_state = STATE_BASE_TS;
break;
case STATE_BASE_TS:
s->s_state = STATE_TS;
read_frclock_64(&s->s_base_tsc);
break;
case STATE_TS:
read_frclock_64(&cur_tsc);
tsc_delta = delta_frclock_64(s->s_base_tsc, cur_tsc);
micro_delta = frclock_64_to_micros(tsc_delta);
if (micro_delta >= s->s_usecs) {
s->s_timeout = TRUE;
return FALSE;
}
if (micro_delta >= TSC_SPIN) {
s->s_usecs -= micro_delta;
getticks(&s->s_base_uptime);
s->s_state = STATE_UPTIME;
}
break;
case STATE_UPTIME:
getticks(&now);
/* We assume that sys_hz() caches its return value. */
micro_delta = ((now - s->s_base_uptime) * 1000 / sys_hz()) *
1000;
if (micro_delta >= s->s_usecs) {
s->s_timeout = TRUE;
return FALSE;
}
break;
default:
panic("spin_check: invalid state %d", s->s_state);
}
return TRUE;
}

View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#include <time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <minix/u64.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/minlib.h>
#include <machine/archtypes.h>
#include "sysutil.h"
#ifndef CONFIG_MAX_CPUS
#define CONFIG_MAX_CPUS 1
#endif
#define MICROHZ 1000000 /* number of micros per second */
#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
static u32_t calib_hz = 600000000;
u32_t tsc_64_to_micros(u64_t tsc)
{
u64_t tmp;
tmp = tsc / calib_hz;
return (u32_t) tmp;
}
u32_t tsc_to_micros(u32_t low, u32_t high)
{
return tsc_64_to_micros(make64(low, high));
}

View File

@@ -8,7 +8,7 @@ SRCS= main.c alloc.c utility.c exit.c fork.c break.c \
mem_anon.c mem_directphys.c mem_anon_contig.c mem_shared.c \
mem_cache.c cache.c vfs.c mem_file.c fdref.c acl.c
.if ${MACHINE_ARCH} == "earm"
.if ((${MACHINE_ARCH} == "earm") || (${MACHINE_ARCH} == "earmv6hf") )
LDFLAGS+= -T ${.CURDIR}/arch/${MACHINE_ARCH}/vm.lds
.endif

View File

@@ -0,0 +1,4 @@
.include <bsd.own.mk>
#Arch-specific sources
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}

View File

@@ -0,0 +1,52 @@
#ifndef _PAGETABLE_H
#define _PAGETABLE_H 1
#include <stdint.h>
#include <machine/vm.h>
#include "vm.h"
/* Mapping flags. */
#define PTF_WRITE ARM_VM_PTE_RW
#define PTF_READ ARM_VM_PTE_RO
#define PTF_PRESENT ARM_VM_PTE_PRESENT
#define PTF_SUPER ARM_VM_PTE_SUPER
#define PTF_USER ARM_VM_PTE_USER
#define PTF_NOCACHE ARM_VM_PTE_DEVICE
#define PTF_CACHEWB ARM_VM_PTE_WB
#define PTF_CACHEWT ARM_VM_PTE_WT
#define PTF_SHARE ARM_VM_PTE_S
#define ARCH_VM_DIR_ENTRIES ARM_VM_DIR_ENTRIES
#define ARCH_BIG_PAGE_SIZE ARM_SECTION_SIZE
#define ARCH_VM_ADDR_MASK ARM_VM_ADDR_MASK
#define ARCH_VM_PDE_MASK ARM_VM_PDE_MASK
#define ARCH_VM_PDE_PRESENT ARM_VM_PDE_PRESENT
#define ARCH_VM_PTE_PRESENT ARM_VM_PTE_PRESENT
#define ARCH_VM_PTE_USER ARM_VM_PTE_USER
#define ARCH_PAGEDIR_SIZE ARM_PAGEDIR_SIZE
#define ARCH_VM_PTE_RW ARM_VM_PTE_RW
#define ARCH_VM_BIGPAGE ARM_VM_SECTION
#define ARCH_VM_PT_ENTRIES ARM_VM_PT_ENTRIES
#define ARCH_VM_PTE_RO ARM_VM_PTE_RO
/* For arch-specific PT routines to check if no bits outside
* the regular flags are set.
*/
#define PTF_ALLFLAGS (PTF_READ|PTF_WRITE|PTF_PRESENT|PTF_SUPER|PTF_USER|PTF_NOCACHE|PTF_CACHEWB|PTF_CACHEWT|PTF_SHARE)
#define PFERR_PROT(e) ((ARM_VM_PFE_FS(e) == ARM_VM_PFE_L1PERM) \
|| (ARM_VM_PFE_FS(e) == ARM_VM_PFE_L2PERM))
#define PFERR_NOPAGE(e) (!PFERR_PROT(e))
#define PFERR_WRITE(e) ((e) & ARM_VM_PFE_W)
#define PFERR_READ(e) (!((e) & ARM_VM_PFE_W))
#define VM_PAGE_SIZE ARM_PAGE_SIZE
/* virtual address -> pde, pte macros */
#define ARCH_VM_PTE(v) ARM_VM_PTE(v)
#define ARCH_VM_PDE(v) ARM_VM_PDE(v)
#endif

Some files were not shown because too many files have changed in this diff Show More