Initial commit - code buildable with rpi
This commit is contained in:
@@ -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"
|
||||
|
||||
7
minix/drivers/bus/i2c/arch/earmv6hf/Makefile.inc
Normal file
7
minix/drivers/bus/i2c/arch/earmv6hf/Makefile.inc
Normal 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
|
||||
876
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c.c
Normal file
876
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c.c
Normal 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;
|
||||
}
|
||||
10
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c.h
Normal file
10
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c.h
Normal 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 */
|
||||
152
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c_registers.h
Normal file
152
minix/drivers/bus/i2c/arch/earmv6hf/omap_i2c_registers.h
Normal 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 */
|
||||
10
minix/drivers/clock/readclock/arch/earmv6hf/Makefile.inc
Normal file
10
minix/drivers/clock/readclock/arch/earmv6hf/Makefile.inc
Normal 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
|
||||
45
minix/drivers/clock/readclock/arch/earmv6hf/arch_readclock.c
Normal file
45
minix/drivers/clock/readclock/arch/earmv6hf/arch_readclock.c
Normal 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;
|
||||
}
|
||||
419
minix/drivers/clock/readclock/arch/earmv6hf/omap_rtc.c
Normal file
419
minix/drivers/clock/readclock/arch/earmv6hf/omap_rtc.c
Normal 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");
|
||||
}
|
||||
94
minix/drivers/clock/readclock/arch/earmv6hf/omap_rtc.h
Normal file
94
minix/drivers/clock/readclock/arch/earmv6hf/omap_rtc.h
Normal 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 */
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
7
minix/drivers/tty/tty/arch/earmv6hf/Makefile.inc
Normal file
7
minix/drivers/tty/tty/arch/earmv6hf/Makefile.inc
Normal 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
|
||||
30
minix/drivers/tty/tty/arch/earmv6hf/console.c
Normal file
30
minix/drivers/tty/tty/arch/earmv6hf/console.c
Normal 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;
|
||||
}
|
||||
30
minix/drivers/tty/tty/arch/earmv6hf/keyboard.c
Normal file
30
minix/drivers/tty/tty/arch/earmv6hf/keyboard.c
Normal 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)
|
||||
{
|
||||
}
|
||||
107
minix/drivers/tty/tty/arch/earmv6hf/omap_serial.h
Normal file
107
minix/drivers/tty/tty/arch/earmv6hf/omap_serial.h
Normal 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 */
|
||||
848
minix/drivers/tty/tty/arch/earmv6hf/rs232.c
Normal file
848
minix/drivers/tty/tty/arch/earmv6hf/rs232.c
Normal 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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
7
minix/drivers/video/fb/arch/earmv6hf/Makefile.inc
Normal file
7
minix/drivers/video/fb/arch/earmv6hf/Makefile.inc
Normal 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
|
||||
65
minix/drivers/video/fb/arch/earmv6hf/dss.h
Normal file
65
minix/drivers/video/fb/arch/earmv6hf/dss.h
Normal 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__ */
|
||||
408
minix/drivers/video/fb/arch/earmv6hf/fb_arch.c
Normal file
408
minix/drivers/video/fb/arch/earmv6hf/fb_arch.c
Normal 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;
|
||||
}
|
||||
|
||||
4
minix/include/arch/earmv6hf/Makefile
Normal file
4
minix/include/arch/earmv6hf/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
SUBDIR= include
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
8
minix/include/arch/earmv6hf/include/Makefile
Normal file
8
minix/include/arch/earmv6hf/include/Makefile
Normal 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>
|
||||
6
minix/include/arch/earmv6hf/include/archconst.h
Normal file
6
minix/include/arch/earmv6hf/include/archconst.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _ARM_CONST_H
|
||||
#define _ARM_CONST_H
|
||||
|
||||
#define DEFAULT_HZ 1000
|
||||
|
||||
#endif /* #ifndef _ARM_CONST_H */
|
||||
27
minix/include/arch/earmv6hf/include/archtypes.h
Normal file
27
minix/include/arch/earmv6hf/include/archtypes.h
Normal 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 */
|
||||
|
||||
20
minix/include/arch/earmv6hf/include/diskparm.h
Normal file
20
minix/include/arch/earmv6hf/include/diskparm.h
Normal 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 */
|
||||
42
minix/include/arch/earmv6hf/include/elf.h
Normal file
42
minix/include/arch/earmv6hf/include/elf.h
Normal 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_ */
|
||||
8
minix/include/arch/earmv6hf/include/interrupt.h
Normal file
8
minix/include/arch/earmv6hf/include/interrupt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* Interrupt numbers and hardware vectors. */
|
||||
|
||||
#ifndef _INTERRUPT_H
|
||||
#define _INTERRUPT_H
|
||||
|
||||
#define NR_IRQ_VECTORS 125
|
||||
|
||||
#endif /* _INTERRUPT_H */
|
||||
9
minix/include/arch/earmv6hf/include/ipcconst.h
Normal file
9
minix/include/arch/earmv6hf/include/ipcconst.h
Normal 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_ */
|
||||
10
minix/include/arch/earmv6hf/include/memory.h
Normal file
10
minix/include/arch/earmv6hf/include/memory.h
Normal 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 */
|
||||
351
minix/include/arch/earmv6hf/include/multiboot.h
Normal file
351
minix/include/arch/earmv6hf/include/multiboot.h
Normal 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__ */
|
||||
28
minix/include/arch/earmv6hf/include/partition.h
Normal file
28
minix/include/arch/earmv6hf/include/partition.h
Normal 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 */
|
||||
28
minix/include/arch/earmv6hf/include/stackframe.h
Normal file
28
minix/include/arch/earmv6hf/include/stackframe.h
Normal 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 */
|
||||
196
minix/include/arch/earmv6hf/include/vm.h
Normal file
196
minix/include/arch/earmv6hf/include/vm.h
Normal 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__ */
|
||||
98
minix/kernel/arch/earmv6hf/Makefile.inc
Normal file
98
minix/kernel/arch/earmv6hf/Makefile.inc
Normal 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
|
||||
|
||||
141
minix/kernel/arch/earmv6hf/arch_clock.c
Normal file
141
minix/kernel/arch/earmv6hf/arch_clock.c
Normal 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;
|
||||
}
|
||||
56
minix/kernel/arch/earmv6hf/arch_do_vmctl.c
Normal file
56
minix/kernel/arch/earmv6hf/arch_do_vmctl.c
Normal 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;
|
||||
}
|
||||
82
minix/kernel/arch/earmv6hf/arch_reset.c
Normal file
82
minix/kernel/arch/earmv6hf/arch_reset.c
Normal 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
|
||||
218
minix/kernel/arch/earmv6hf/arch_system.c
Normal file
218
minix/kernel/arch/earmv6hf/arch_system.c
Normal 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;
|
||||
}
|
||||
7
minix/kernel/arch/earmv6hf/bsp/include/bsp_init.h
Normal file
7
minix/kernel/arch/earmv6hf/bsp/include/bsp_init.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef _BSP_INIT_H_
|
||||
#define _BSP_INIT_H_
|
||||
|
||||
/* BSP init */
|
||||
void bsp_init();
|
||||
|
||||
#endif /* __BSP_INIT_H__ */
|
||||
12
minix/kernel/arch/earmv6hf/bsp/include/bsp_intr.h
Normal file
12
minix/kernel/arch/earmv6hf/bsp/include/bsp_intr.h
Normal 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_ */
|
||||
11
minix/kernel/arch/earmv6hf/bsp/include/bsp_padconf.h
Normal file
11
minix/kernel/arch/earmv6hf/bsp/include/bsp_padconf.h
Normal 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_ */
|
||||
9
minix/kernel/arch/earmv6hf/bsp/include/bsp_reset.h
Normal file
9
minix/kernel/arch/earmv6hf/bsp/include/bsp_reset.h
Normal 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_ */
|
||||
6
minix/kernel/arch/earmv6hf/bsp/include/bsp_serial.h
Normal file
6
minix/kernel/arch/earmv6hf/bsp/include/bsp_serial.h
Normal 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_ */
|
||||
13
minix/kernel/arch/earmv6hf/bsp/include/bsp_timer.h
Normal file
13
minix/kernel/arch/earmv6hf/bsp/include/bsp_timer.h
Normal 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_ */
|
||||
13
minix/kernel/arch/earmv6hf/bsp/ti/Makefile.inc
Normal file
13
minix/kernel/arch/earmv6hf/bsp/ti/Makefile.inc
Normal 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
|
||||
|
||||
21
minix/kernel/arch/earmv6hf/bsp/ti/omap_init.c
Normal file
21
minix/kernel/arch/earmv6hf/bsp/ti/omap_init.c
Normal 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();
|
||||
}
|
||||
72
minix/kernel/arch/earmv6hf/bsp/ti/omap_intr.c
Normal file
72
minix/kernel/arch/earmv6hf/bsp/ti/omap_intr.c
Normal 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));
|
||||
}
|
||||
236
minix/kernel/arch/earmv6hf/bsp/ti/omap_intr_registers.h
Normal file
236
minix/kernel/arch/earmv6hf/bsp/ti/omap_intr_registers.h
Normal 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 */
|
||||
83
minix/kernel/arch/earmv6hf/bsp/ti/omap_padconf.c
Normal file
83
minix/kernel/arch/earmv6hf/bsp/ti/omap_padconf.c
Normal 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;
|
||||
}
|
||||
100
minix/kernel/arch/earmv6hf/bsp/ti/omap_reset.c
Normal file
100
minix/kernel/arch/earmv6hf/bsp/ti/omap_reset.c
Normal 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) ;
|
||||
}
|
||||
}
|
||||
|
||||
58
minix/kernel/arch/earmv6hf/bsp/ti/omap_rtc.c
Normal file
58
minix/kernel/arch/earmv6hf/bsp/ti/omap_rtc.c
Normal 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));
|
||||
}
|
||||
}
|
||||
7
minix/kernel/arch/earmv6hf/bsp/ti/omap_rtc.h
Normal file
7
minix/kernel/arch/earmv6hf/bsp/ti/omap_rtc.h
Normal 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 */
|
||||
84
minix/kernel/arch/earmv6hf/bsp/ti/omap_serial.c
Normal file
84
minix/kernel/arch/earmv6hf/bsp/ti/omap_serial.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
minix/kernel/arch/earmv6hf/bsp/ti/omap_serial.h
Normal file
27
minix/kernel/arch/earmv6hf/bsp/ti/omap_serial.h
Normal 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 */
|
||||
397
minix/kernel/arch/earmv6hf/bsp/ti/omap_timer.c
Normal file
397
minix/kernel/arch/earmv6hf/bsp/ti/omap_timer.c
Normal 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 = ®s_v1
|
||||
};
|
||||
|
||||
/* free running timer */
|
||||
static struct omap_timer dm37xx_fr_timer = {
|
||||
.base = OMAP3_GPTIMER10_BASE,
|
||||
.irq_nr = OMAP3_GPT10_IRQ,
|
||||
.regs = ®s_v1
|
||||
};
|
||||
|
||||
/* normal timer */
|
||||
static struct omap_timer am335x_timer = {
|
||||
.base = AM335X_DMTIMER1_1MS_BASE,
|
||||
.irq_nr = AM335X_INT_TINT1_1MS,
|
||||
.regs = ®s_v1
|
||||
};
|
||||
|
||||
/* free running timer */
|
||||
static struct omap_timer am335x_fr_timer = {
|
||||
.base = AM335X_DMTIMER7_BASE,
|
||||
.irq_nr = AM335X_INT_TINT7,
|
||||
.regs = ®s_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);
|
||||
}
|
||||
157
minix/kernel/arch/earmv6hf/bsp/ti/omap_timer_registers.h
Normal file
157
minix/kernel/arch/earmv6hf/bsp/ti/omap_timer_registers.h
Normal 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 */
|
||||
30
minix/kernel/arch/earmv6hf/direct_tty_utils.c
Normal file
30
minix/kernel/arch/earmv6hf/direct_tty_utils.c
Normal 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;
|
||||
}
|
||||
18
minix/kernel/arch/earmv6hf/do_padconf.c
Normal file
18
minix/kernel/arch/earmv6hf/do_padconf.c
Normal 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 */
|
||||
22
minix/kernel/arch/earmv6hf/exc.S
Normal file
22
minix/kernel/arch/earmv6hf/exc.S
Normal 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 .
|
||||
232
minix/kernel/arch/earmv6hf/exception.c
Normal file
232
minix/kernel/arch/earmv6hf/exception.c
Normal 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)
|
||||
{
|
||||
}
|
||||
9
minix/kernel/arch/earmv6hf/glo.h
Normal file
9
minix/kernel/arch/earmv6hf/glo.h
Normal 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__ */
|
||||
54
minix/kernel/arch/earmv6hf/head.S
Normal file
54
minix/kernel/arch/earmv6hf/head.S
Normal 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:
|
||||
16
minix/kernel/arch/earmv6hf/hw_intr.c
Normal file
16
minix/kernel/arch/earmv6hf/hw_intr.c
Normal 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(){};
|
||||
6
minix/kernel/arch/earmv6hf/include/arch_clock.h
Normal file
6
minix/kernel/arch/earmv6hf/include/arch_clock.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __CLOCK_ARM_H__
|
||||
#define __CLOCK_ARM_H__
|
||||
|
||||
void arch_timer_int_handler(void);
|
||||
|
||||
#endif /* __CLOCK_ARM_H__ */
|
||||
125
minix/kernel/arch/earmv6hf/include/arch_proto.h
Normal file
125
minix/kernel/arch/earmv6hf/include/arch_proto.h
Normal 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
|
||||
6
minix/kernel/arch/earmv6hf/include/arch_watchdog.h
Normal file
6
minix/kernel/arch/earmv6hf/include/arch_watchdog.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __ARM_WATCHDOG_H__
|
||||
#define __ARM_WATCHDOG_H__
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#endif /* __ARM_WATCHDOG_H__ */
|
||||
41
minix/kernel/arch/earmv6hf/include/archconst.h
Normal file
41
minix/kernel/arch/earmv6hf/include/archconst.h
Normal 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 */
|
||||
22
minix/kernel/arch/earmv6hf/include/ccnt.h
Normal file
22
minix/kernel/arch/earmv6hf/include/ccnt.h
Normal 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 */
|
||||
463
minix/kernel/arch/earmv6hf/include/cpufunc.h
Normal file
463
minix/kernel/arch/earmv6hf/include/cpufunc.h
Normal 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 */
|
||||
11
minix/kernel/arch/earmv6hf/include/direct_utils.h
Normal file
11
minix/kernel/arch/earmv6hf/include/direct_utils.h
Normal 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
|
||||
15
minix/kernel/arch/earmv6hf/include/hw_intr.h
Normal file
15
minix/kernel/arch/earmv6hf/include/hw_intr.h
Normal 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__ */
|
||||
16
minix/kernel/arch/earmv6hf/include/io.h
Normal file
16
minix/kernel/arch/earmv6hf/include/io.h
Normal 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_ */
|
||||
50
minix/kernel/arch/earmv6hf/kernel.lds
Normal file
50
minix/kernel/arch/earmv6hf/kernel.lds
Normal 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*)
|
||||
}
|
||||
}
|
||||
107
minix/kernel/arch/earmv6hf/klib.S
Normal file
107
minix/kernel/arch/earmv6hf/klib.S
Normal 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
|
||||
899
minix/kernel/arch/earmv6hf/memory.c
Normal file
899
minix/kernel/arch/earmv6hf/memory.c
Normal 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);
|
||||
}
|
||||
|
||||
289
minix/kernel/arch/earmv6hf/mpx.S
Normal file
289
minix/kernel/arch/earmv6hf/mpx.S
Normal 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 */
|
||||
317
minix/kernel/arch/earmv6hf/pg_utils.c
Normal file
317
minix/kernel/arch/earmv6hf/pg_utils.c
Normal 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;
|
||||
}
|
||||
397
minix/kernel/arch/earmv6hf/phys_copy.S
Normal file
397
minix/kernel/arch/earmv6hf/phys_copy.S
Normal 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
|
||||
274
minix/kernel/arch/earmv6hf/phys_memset.S
Normal file
274
minix/kernel/arch/earmv6hf/phys_memset.S
Normal 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
|
||||
426
minix/kernel/arch/earmv6hf/pre_init.c
Normal file
426
minix/kernel/arch/earmv6hf/pre_init.c
Normal 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 */
|
||||
24
minix/kernel/arch/earmv6hf/procoffsets.cf
Normal file
24
minix/kernel/arch/earmv6hf/procoffsets.cf
Normal 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
|
||||
|
||||
183
minix/kernel/arch/earmv6hf/protect.c
Normal file
183
minix/kernel/arch/earmv6hf/protect.c
Normal 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;
|
||||
}
|
||||
}
|
||||
7
minix/kernel/arch/earmv6hf/sconst.h
Normal file
7
minix/kernel/arch/earmv6hf/sconst.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef __SCONST_H__
|
||||
#define __SCONST_H__
|
||||
|
||||
#include "kernel/const.h"
|
||||
#include "kernel/procoffsets.h"
|
||||
|
||||
#endif /* __SCONST_H__ */
|
||||
7
minix/kernel/arch/earmv6hf/timer.h
Normal file
7
minix/kernel/arch/earmv6hf/timer.h
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
#ifndef _KERN_TIMER_H
|
||||
#define _KERN_TIMER_H
|
||||
|
||||
#include "omap_timer.h"
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
99
minix/lib/libminc/arch/earmv6hf/Makefile.libc.inc
Normal file
99
minix/lib/libminc/arch/earmv6hf/Makefile.libc.inc
Normal 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
|
||||
15
minix/lib/libsys/arch/earmv6hf/Makefile.inc
Normal file
15
minix/lib/libsys/arch/earmv6hf/Makefile.inc
Normal 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}/
|
||||
|
||||
|
||||
92
minix/lib/libsys/arch/earmv6hf/frclock_util.c
Normal file
92
minix/lib/libsys/arch/earmv6hf/frclock_util.c
Normal 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);
|
||||
}
|
||||
|
||||
98
minix/lib/libsys/arch/earmv6hf/spin.c
Normal file
98
minix/lib/libsys/arch/earmv6hf/spin.c
Normal 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;
|
||||
}
|
||||
35
minix/lib/libsys/arch/earmv6hf/tsc_util.c
Normal file
35
minix/lib/libsys/arch/earmv6hf/tsc_util.c
Normal 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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
4
minix/servers/vm/arch/earmv6hf/Makefile.inc
Normal file
4
minix/servers/vm/arch/earmv6hf/Makefile.inc
Normal file
@@ -0,0 +1,4 @@
|
||||
.include <bsd.own.mk>
|
||||
|
||||
#Arch-specific sources
|
||||
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
52
minix/servers/vm/arch/earmv6hf/pagetable.h
Normal file
52
minix/servers/vm/arch/earmv6hf/pagetable.h
Normal 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
Reference in New Issue
Block a user