1
0

devices -> drivers

This commit is contained in:
2012-10-03 23:30:19 -04:00
parent 9b66a78569
commit 3f624153e7
15 changed files with 7 additions and 7 deletions

69
drivers/bcm2835_mailbox.c Normal file

@ -0,0 +1,69 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
/* Mailbox Memory-Mapped Registers */
#define VC_MMU_IO_OFFSET(addr) (addr - 0x7E000000 + 0x20000000)
#define MBOX0_READ VC_MMU_IO_OFFSET(0x7E00B880)
/* MBOX0_READ layout:
31-4 data The 28 bits of data sent to the CPU
3-0 channel The mailbox channel number from which the data originated */
#define MBOX0_PEEK VC_MMU_IO_OFFSET(0x7E00B890) //Read from the mailbox without removing data from it.
#define MBOX0_SENDER VC_MMU_IO_OFFSET(0x7E00B894) //Sender ID (bottom 2 bits only)
#define MBOX0_STATUS VC_MMU_IO_OFFSET(0x7E00B898)
/* MBOX0_STATUS layout:
31 full Set if the mailbox is full, and thus no more data can be written to it.
30 empty Set if the mailbox is empty, and thus no more data is available to be read from it.
29-0 unused? */
#define MBOX0_CONFIG VC_MMU_IO_OFFSET(0x7E00B89C)
#define MBOX0_WRITE VC_MMU_IO_OFFSET(0x7E00B8A0) //also MBOX1_READ?
/* MBOX0_WRITE layout:
31-4 data The 28 bits of data to be sent
3-0 channel The mailbox channel to send data to */
#define MBOX0_STATUS_FULL 0x80000000
#define MBOX0_STATUS_EMPTY 0x40000000
uint32 mailbox_read(uint32 channel) {
uint32 mbox_msg;
while (1) {
int i;
for (i = 0; *(volatile uint32 *)MBOX0_STATUS & MBOX0_STATUS_EMPTY; i++) {
if (i >= 1<<20)
return 0xFFFFFFFF;
}
mbox_msg = *(volatile uint32 *)MBOX0_READ;
if ((mbox_msg & 0xf) == channel)
return mbox_msg & ~0xf;
}
}
void mailbox_write(uint32 channel, uint32 data) {
channel &= 0xf;
data &= ~0xf;
while (*(volatile uint32 *)MBOX0_STATUS & MBOX0_STATUS_FULL);
*(volatile uint32 *)MBOX0_WRITE = channel | data;
}

@ -0,0 +1,94 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
#include <framebuffer.h>
#include <kmalloc.h>
#include <print.h>
#include <drivers/bcm2835_mailbox.h>
struct bcm2835_config {
uint32 width;
uint32 height;
uint32 vwidth;
uint32 vheight;
uint32 pitch;
uint32 color_depth;
uint32 xoffset;
uint32 yoffset;
uint32 fb_base_addr;
uint32 size;
};
#define MAILBOX_BUFFER_SIZE (32*4*2)
#define FB_WIDTH 1024
#define FB_HEIGHT 768
struct fbdev bcm2835_fb_device;
int bcm2835_videocore_init(struct fb *f, unsigned int color_depth) {
struct bcm2835_config *cfg;
uint32 result;
void *mailbox_buffer_orig, *mailbox_buffer;
if (!(mailbox_buffer_orig = kmalloc(MAILBOX_BUFFER_SIZE))) {
return -1;
}
/* Round mailbox buffer to multiple of 0x10 because the low 4 bits of
the mailbox are used to send the channel, and therefore can't hold the low 4
bits of the address */
if ((uint32)mailbox_buffer_orig & 0xf)
mailbox_buffer = (void *)((uint32)mailbox_buffer_orig & ~0xf) + 0x10;
else
mailbox_buffer = mailbox_buffer_orig;
cfg = (struct bcm2835_config *)mailbox_buffer;
cfg->width = FB_WIDTH;
cfg->height = FB_HEIGHT;
cfg->vwidth = FB_WIDTH;
cfg->vheight = FB_HEIGHT;
cfg->pitch = 0;
cfg->color_depth = color_depth;
cfg->xoffset = 0;
cfg->yoffset = 0;
cfg->fb_base_addr = 0;
cfg->size = 0;
mailbox_write(MBOX_FB, (uint32)cfg);
result = mailbox_read(MBOX_FB);
if (result || !cfg->fb_base_addr) {
print("Error: did not request a proper framebuffer\n");
return -1;
}
f->device = &bcm2835_fb_device;
f->device->fbaddr = (void*)cfg->fb_base_addr;
f->width = cfg->width;
f->device->pixelwidth = cfg->width;
f->height = cfg->height;
f->device->pixelheight = cfg->height;
f->color_depth = color_depth;
f->device->color_depth = color_depth;
return 0;
}

20
drivers/kernel.mk Normal file

@ -0,0 +1,20 @@
DIRNAME := drivers
SUBDIRS :=
include $(BASEDIR)/header.mk
OBJS_$(d)_$(CONFIG_VEXPRESS_A9) := \
$(d)/pl011.o \
$(d)/pl111.o
OBJS_$(d)_$(CONFIG_INTEGRATOR_CP) := \
$(d)/pl110.o \
OBJS_$(d)_$(CONFIG_RPI) := \
$(d)/pi_mini_uart.o \
$(d)/bcm2835_mailbox.o \
$(d)/bcm2835_videocore.o
KOBJS += $(OBJS_$(d)_y)
include $(BASEDIR)/footer.mk

105
drivers/pi_mini_uart.c Normal file

@ -0,0 +1,105 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
#define VC_MMU_IO_OFFSET(addr) (addr - 0x7E000000 + 0x20000000)
/* Auxiliary IO registers (includes both mini-UART and SPI) */
#define AUX_IRQ VC_MMU_IO_OFFSET(0x7E215000)
#define AUX_ENABLES VC_MMU_IO_OFFSET(0x7E215004)
#define AUX_MU_IO_REG VC_MMU_IO_OFFSET(0x7E215040)
#define AUX_MU_IER_REG VC_MMU_IO_OFFSET(0x7E215044)
#define AUX_MU_IIR_REG VC_MMU_IO_OFFSET(0x7E215048)
#define AUX_MU_LCR_REG VC_MMU_IO_OFFSET(0x7E21504C)
#define AUX_MU_MCR_REG VC_MMU_IO_OFFSET(0x7E215050)
#define AUX_MU_LSR_REG VC_MMU_IO_OFFSET(0x7E215054)
#define AUX_MU_MSR_REG VC_MMU_IO_OFFSET(0x7E215058)
#define AUX_MU_SCRATCH VC_MMU_IO_OFFSET(0x7E21505C)
#define AUX_MU_CNTL_REG VC_MMU_IO_OFFSET(0x7E215060)
#define AUX_MU_STAT_REG VC_MMU_IO_OFFSET(0x7E215064)
#define AUX_MU_BAUD_REG VC_MMU_IO_OFFSET(0x7E215068)
#define AUX_SPI0_CNTL0_REG VC_MMU_IO_OFFSET(0x7E215080)
#define AUX_SPI0_CNTL1_REG VC_MMU_IO_OFFSET(0x7E215084)
#define AUX_SPI0_STAT_REG VC_MMU_IO_OFFSET(0x7E215088)
#define AUX_SPI0_IO_REG VC_MMU_IO_OFFSET(0x7E215090)
#define AUX_SPI0_PEEK_REG VC_MMU_IO_OFFSET(0x7E215094)
#define AUX_SPI1_CNTL0_REG VC_MMU_IO_OFFSET(0x7E2150C0)
#define AUX_SPI1_CNTL1_REG VC_MMU_IO_OFFSET(0x7E2150C4)
#define AUX_SPI1_STAT_REG VC_MMU_IO_OFFSET(0x7E2150C8)
#define AUX_SPI1_IO_REG VC_MMU_IO_OFFSET(0x7E2150D0)
#define AUX_SPI1_PEEK_REG VC_MMU_IO_OFFSET(0x7E2150D4)
/* Constants for mini-UART operation */
#define MINI_UART_TX_EMPTY 0x20
/* General GPIO pin registers */
#define GPFSEL1 VC_MMU_IO_OFFSET(0x7E200004)
#define GPSET0 VC_MMU_IO_OFFSET(0x7E20001C)
#define GPCLR0 VC_MMU_IO_OFFSET(0x7E200028)
#define GPPUD VC_MMU_IO_OFFSET(0x7E200094)
#define GPPUDCLK0 VC_MMU_IO_OFFSET(0x7E200098)
void mini_uart_init() {
uint32 aux_enables;
uint32 gpfsel1;
unsigned int i;
/* Enable the mini-UART */
aux_enables = (*(uint32 *)AUX_ENABLES) & 0x7;
*(uint32 *)AUX_ENABLES = aux_enables | 0x1;
//TODO are these all necessary?
*(uint32 *)AUX_MU_IER_REG = 0; //disable interrupts
*(uint32 *)AUX_MU_CNTL_REG = 0; //disable RX and TX
*(uint32 *)AUX_MU_LCR_REG = 3; //set to 8-bit mode (though this only takes setting bit 0, no clue why bit 1 is set too)
*(uint32 *)AUX_MU_MCR_REG = 0; //"If clear the UART1_RTS line is high If set the UART1_RTS line is low"
*(uint32 *)AUX_MU_IER_REG = 0; //disable interrupts again?
*(uint32 *)AUX_MU_IIR_REG = 0xC6; //why are we setting the interrupt status - this looks like a read-only register?
//also, the manual says setting bits 2&3 simultaneously shouldn't be possible...
// baudrate = system_clock_freq / ( 8 * (baudrate_reg + 1))
// baudrate_reg = system_clock_freq / baudrate / 8 - 1
// baudrate_reg = 250000000 / 115200 / 8 - 1 = 270
*(uint32 *)AUX_MU_BAUD_REG = 270;
//set the GPIO pin to the alternate function for this UART
gpfsel1 = (*(uint32 *)GPFSEL1) & ~(7<<12); //get the GPIO Function Select 1 register, and keep all the bits except those that are for GPIO pin 14
gpfsel1 |= 2<<12; // set to 010 (GPIO Pin 14 takes alternate function 5)
*(uint32 *)GPFSEL1 = gpfsel1;
//Follow the procedure for change pull-up/pull-down status (see page 101 of the BCM2835 ARM Peripherals datasheet)
*(uint32 *)GPPUD = 0; //disable pull-up/pull-down for those pins which receive a write to their bit in GPPUDCLK0/1
for(i = 0; i < 150; i++) asm(""); //wait at least 150 cycles
*(uint32 *)GPPUDCLK0 = 1<<14; //"Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to modify" (in our case, this is 14)
for(i = 0; i < 150; i++) asm(""); //wait at least 150 cycles
// *(uint32 *)GPPUD = 0; //remove the signal (shouldn't really be necessary since it was 0 anyway in our case)
*(uint32 *)GPPUDCLK0 = 0; //clear the clock
*(uint32 *)AUX_MU_CNTL_REG = 2; //enable TX
}
void mini_uart_putc(char c) {
/* Wait until the serial buffer is empty */
while (!(*(volatile uint32*)AUX_MU_LSR_REG & MINI_UART_TX_EMPTY));
/* When it's empty, write our character */
*(volatile uint32*)AUX_MU_IO_REG = c;
}

34
drivers/pl011.c Normal file

@ -0,0 +1,34 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
#define PL011_SERIAL_BASE 0x10009000
#define PL011_SERIAL_FLAG_REGISTER 0x18
#define PL011_SERIAL_BUFFER_FULL (1 << 5)
void pl011_putc(char c)
{
/* Wait until the serial buffer is empty */
while (*(volatile uint32*)(PL011_SERIAL_BASE + PL011_SERIAL_FLAG_REGISTER) & (PL011_SERIAL_BUFFER_FULL));
/* When it's empty, put our character at the base */
*(volatile uint32*)PL011_SERIAL_BASE = c;
}

90
drivers/pl110.c Normal file

@ -0,0 +1,90 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
#include <framebuffer.h>
#include <mm.h>
#include <math.h>
#define PL110_CR_EN 0x001
#define PL110_CR_PWR 0x800
#define PL110_IOBASE 0xc0000000
#define PL110_PALBASE (PL110_IOBASE + 0x200)
struct pl110_control {
uint32 volatile timing0; //0
uint32 volatile timing1; //4
uint32 volatile timing2; //8
uint32 volatile timing3; //c
uint32 volatile upbase; //10
uint32 volatile lpbase; //14
uint32 volatile intrenable; //18
uint32 volatile control; //1c
};
struct fbdev pl110_fb_device;
int pl110_init(struct fb *f, unsigned int color_depth) {
unsigned int width, height;
unsigned int fb_size, power;
struct pl110_control *plio = (struct pl110_control*)PL110_IOBASE;
struct page *p;
/* 640x480 pixels */
width = 640;
height = 480;
plio->timing0 = 0x3f1f3f9c;
plio->timing1 = 0x080b61df;
/* Allocate memory for framebuffer */
fb_size = width * height * (color_depth / 8);
power = log(fb_size) - log(MM_PAGE_SIZE);
if ((unsigned int)1<<power < fb_size)
power++;
p = mm_get_free_pages(power);
if (!p)
return -1;
plio->upbase = (uint32)p->address;
if (color_depth == FB_COLOR_DEPTH_8) {
plio->control = 0x1827;
} else if (color_depth == FB_COLOR_DEPTH_16) {
plio->control = 0x1829;
} else if (color_depth == FB_COLOR_DEPTH_24) {
plio->control = 0x182B;
} else {
//assume 16 if nothing else fit
color_depth = 16;
plio->control = 0x1829;
}
f->device = &pl110_fb_device;
f->device->fbaddr = (void*)plio->upbase;
f->width = width;
f->device->pixelwidth = width;
f->height = height;
f->device->pixelheight = height;
f->color_depth = color_depth;
f->device->color_depth = color_depth;
return 0;
}

89
drivers/pl111.c Normal file

@ -0,0 +1,89 @@
/*
Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
This file is part of Aedrix.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <types.h>
#include <framebuffer.h>
#include <mm.h>
#include <math.h>
#define PL111_CR_EN 0x001
#define PL111_CR_PWR 0x800
#define PL111_IOBASE 0x10020000
#define PL111_PALBASE (PL111_IOBASE + 0x200)
struct pl111_control {
uint32 volatile timing0; //0
uint32 volatile timing1; //4
uint32 volatile timing2; //8
uint32 volatile timing3; //c
uint32 volatile upbase; //10
uint32 volatile lpbase; //14
uint32 volatile control; //18
};
struct fbdev pl111_fb_device;
int pl111_init(struct fb *f, unsigned int color_depth) {
unsigned int width, height;
unsigned int fb_size, power;
struct pl111_control *plio = (struct pl111_control*)PL111_IOBASE;
struct page *p;
/* 640x480 pixels */
width = 640;
height = 480;
plio->timing0 = 0x3f1f3f9c;
plio->timing1 = 0x080b61df;
/* Allocate memory for framebuffer */
fb_size = width * height * (color_depth / 8);
power = log(fb_size) - log(MM_PAGE_SIZE);
if ((unsigned int)1<<power < fb_size)
power++;
p = mm_get_free_pages(power);
if (!p)
return -1;
plio->upbase = (uint32)p->address;
if (color_depth == FB_COLOR_DEPTH_8) {
plio->control = 0x1827;
} else if (color_depth == FB_COLOR_DEPTH_16) {
plio->control = 0x1829;
} else if (color_depth == FB_COLOR_DEPTH_24) {
plio->control = 0x182B;
} else {
//assume 16 if nothing else fit
color_depth = 16;
plio->control = 0x1829;
}
f->device = &pl111_fb_device;
f->device->fbaddr = (void*)plio->upbase;
f->width = width;
f->device->pixelwidth = width;
f->height = height;
f->device->pixelheight = height;
f->color_depth = color_depth;
f->device->color_depth = color_depth;
return 0;
}