Subject: Fwd: question about mmap
To: None <tech-kern@netbsd.org>
From: Chan-youn Park <phygeeks@gmail.com>
List: tech-kern
Date: 03/10/2005 09:34:21
---------- Forwarded message ----------
From: Chan-youn Park <phygeeks@gmail.com>
Date: Thu, 10 Mar 2005 09:20:29 +0900
Subject: Re: question about mmap
To: Jachym Holecek <freza@liberouter.org>
On Wed, 9 Mar 2005 10:01:57 +0100, Jachym Holecek <freza@liberouter.org> wrote:
> Hi,
>
> > [... Can't bus_space_mmap(), mmap routine looks correct ...]
> >
> > here, pmemt and pmema is the tag and physical address of the DSP
> > memory space which are get using pci_mapreg_info.
>
> Just to make sure -- do you 1) also call pci_mapreg_map() or 2) call
> bus_space_map() before allowing accessing that space by method?
I call bus_space_map() using the information get from pci_mapreg_info().
> Btw, memory protection value of "1" you're seeing is relevant and means
> "allow reads" (PROT_READ that is, see /usr/include/sys/mman.h), which is
> correct.
Yes of course. What I meant was I was reading the DSP memory space,
and so PROT_READ will do.
> > And below is a part of a test application program to see the DSP memory space.
> > ----
> > tdsph = open("/dev/tdsp", O_RDWR, 0);
> > sram.addr = mmap(0, sram.len, PROT_READ, MAP_SHARED, tdsph,
> > (off_t)sram.offset);
>
> Does mmap() succeed? Is sram.offset really correct (relative to start of
> SRAM window)?
Unfortunately yes. And offset is also correct because if I use the
offset to display the DSP memory space in kernel (I give the offset to
kernel by ioctl, for debugging), I get the correct results. (I
initialized the DSP memory for each address to contain the value of
its address).
> > while(i < sram.len){
> > addr = (u_int8_t*)sram.addr + i;
> > [...]
>
> Does the DSP SRAM (and the bus hierarchy it's connected to) allow you 8bit
> accesses?
I'm not sure, but I've used 8 bit accesses in kernel, so I think yes.
> > What should I check to see what is wrong? And in addition, is there a
> > good simple code that I can study the usage of device mmap function?
>
> Hmm, I couldn't see anything obviously wrong. After checking the
> questions above, we can look at more code...
>
> Regards,
> -- Jachym Holecek
>
Well then It's time to attach the whole code itself ;)
First some attach routines for DSP drivers.
----
/* $XEplus: tdsp_pci.c,v 1.1 2004/12/22 06:56:45 hebites Exp $ */
/*
* DSP (TMS320C6415) pci attach routine
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <arch/sandpoint/xepro/tdsp_reg.h>
#include <arch/sandpoint/xepro/tdsp.h>
#define HERE printf("%s:%d\n", __FUNCTION__, __LINE__)
/*
* TMS320C6x DSP product info
*/
struct tdsp_pci_product {
u_int32_t tpp_vendorid; /* PCI Vendor ID */
u_int32_t tpp_prodid; /* PCI Product ID */
const char *tpp_name; /* device name */
bus_addr_t tpp_pmembase; /* base 0 offset, prefetchable */
bus_addr_t tpp_npmembase; /* base 1 offset, non-prefetchable */
bus_addr_t tpp_iobase; /* base 2 offset, io space */
};
const struct tdsp_pci_product tdsp_pci_products[] = {
/* TMS320c64x */
{
PCI_VENDOR_TI,
PCI_PRODUCT_TI_TMS320C6415,
"Texas Instruments TMS320C6415 DSP",
0x10, /* Base 0 offset, prefetchable memory */
0x14, /* Base 1 offset, non-prefetchable memory */
0x18, /* Base 2 offset, I/O space */
},
/* other products might come here */
/* the end of tdsp_pci_products */
{ 0, 0, NULL, 0, 0, 0}
};
static const struct tdsp_pci_product*
tdsp_pci_lookup(const struct pci_attach_args*);
int tdsp_pci_match __P((struct device *, struct cfdata *, void *));
void tdsp_pci_attach __P((struct device *, struct device *, void *));
struct cfattach tdsp_pci_ca = {
sizeof(struct tdsp_softc),
tdsp_pci_match,
tdsp_pci_attach
};
int
tdsp_pci_match(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
if (tdsp_pci_lookup(pa) != NULL)
return (1);
return (0);
}
void
tdsp_pci_attach(struct device *parent, struct device *self, void *aux)
{
struct tdsp_softc *sc = (struct tdsp_softc *)self;
struct pci_attach_args *pa = aux;
pci_intr_handle_t ih;
/* Bus space tag & handle for PCI I/O memory space BAR */
bus_space_tag_t iot;
bus_space_handle_t ioh;
/* Bus space tag & handle for PCI prefetchable memory space BAR */
bus_space_tag_t pmemt;
bus_space_handle_t pmemh;
/* Bus space tag & handle for PCI nonprefetchable memory space BAR */
bus_space_tag_t npmemt;
bus_space_handle_t npmemh;
int io_valid, pmem_valid, npmem_valid;
const struct tdsp_pci_product *tpp;
const char *intrstr = NULL;
bus_addr_t addr;
bus_size_t size;
int flags;
int pci_mapreg_info_retval;
/* Check if the found one is the right DSP */
tpp = tdsp_pci_lookup(pa);
if (tpp == NULL) {
ERROR("%s: couldn't find chip id\n", sc->sc_dev.dv_xname);
return;
}
/* Map BAR2(I/O) register */
io_valid =
(pci_mapreg_map(
pa,
tpp->tpp_iobase,
PCI_MAPREG_TYPE_IO,
0,
&iot,
&ioh,
NULL,
NULL) == 0);
/* Map BAR0(prefetchable) register */
pmem_valid = 0;
pmemt = pa->pa_memt;
pci_mapreg_info_retval =
pci_mapreg_info(
pa->pa_pc,
pa->pa_tag,
tpp->tpp_pmembase,
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
&addr,
&size,
&flags);
if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) &&
(pci_mapreg_info_retval == 0)){
flags &= BUS_SPACE_MAP_PREFETCHABLE;
if (bus_space_map(pmemt, addr, size, flags, &pmemh) == 0) {
sc->sc_pmema = addr;
pmem_valid = 1;
}
}
/* Map BAR1(non-prefetchable) register */
npmem_valid = 0;
npmemt = pa->pa_memt;
pci_mapreg_info_retval =
pci_mapreg_info(
pa->pa_pc,
pa->pa_tag,
tpp->tpp_npmembase,
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
&addr,
&size,
&flags);
if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) &&
(pci_mapreg_info_retval == 0)){
flags &= ~BUS_SPACE_MAP_PREFETCHABLE;
if (bus_space_map(npmemt, addr, size, flags, &npmemh) == 0) {
sc->sc_npmema = addr;
npmem_valid = 1;
}
}
/*
* If all the above mappings are successful,
* save tags & handles of the mapped bus space
*/
if (io_valid && pmem_valid && npmem_valid) {
sc->sc_pmemt = pmemt;
sc->sc_pmemh = pmemh;
sc->sc_npmemt = npmemt;
sc->sc_npmemh = npmemh;
sc->sc_iot = iot;
sc->sc_ioh = ioh;
} else {
ERROR(": unable to map device registers\n");
ERROR("\tio_valid = %d, pmem_valid = %d, npmem_valid = %d\n",
io_valid, pmem_valid, npmem_valid);
return;
}
printf(": %s, rev %d\n", tpp->tpp_name, PCI_REVISION(pa->pa_class));
/* DMA setting */
/* XXX Is this necessary? */
sc->sc_dmat = pa->pa_dmat;
/* Make sure bus-mastering is enabled. */
/* XXX is this necessary? */
pci_conf_write(
pa->pa_pc,
pa->pa_tag,
PCI_COMMAND_STATUS_REG,
pci_conf_read(
pa->pa_pc,
pa->pa_tag,
PCI_COMMAND_STATUS_REG) | PCI_COMMAND_MASTER_ENABLE);
/* Map and establish our interrupt */
if (pci_intr_map(pa, &ih)) {
ERROR("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
return;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
/* XXX Is IPL_NET OK for the priority level of this PCI bus? */
sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, tdspintr, sc);
if (sc->sc_ih == NULL) {
ERROR("%s: couldn't establish interrupt",
sc->sc_dev.dv_xname);
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
return;
}
printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
/* Finish off the attach. */
tdsp_attach(sc);
}
static const struct tdsp_pci_product *
tdsp_pci_lookup(const struct pci_attach_args *pa)
{
const struct tdsp_pci_product *tpp;
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_TI)
return (NULL);
for (tpp = tdsp_pci_products; tpp->tpp_name != NULL; tpp++)
if (PCI_PRODUCT(pa->pa_id) == tpp->tpp_prodid)
return (tpp);
return (NULL);
}
----
and DSP device driver itself
----
/* $XEplus: tdsp.c,v 1.1 2004/12/22 06:56:45 hebites Exp $ */
/*
* TDSP320C6415 DSP Device
*/
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <machine/bus.h>
#include <arch/sandpoint/xepro/tdsp_reg.h>
#include <arch/sandpoint/xepro/tdsp.h>
#include "talker_code.h"
/* Structure for convenient EMIF initialization */
typedef struct emif_config {
const char *name; /* Name of the register */
u_int32_t addr; /* Address of the register */
u_int32_t val; /* Value of the register to write */
}emif_config_t;
const emif_config_t emifa[] = {
{"EMIFA_GBLCTL", TDSP_EMIFB_GBLCTL, 0x00012004},
{"EMIFA_SDCTL", TDSP_EMIFB_SDCTL, 0x63117000},
{"EMIFA_SDTIM", TDSP_EMIFB_SDTIM, 0x02000600},
{"EMIFA_CE0CTL", TDSP_EMIFB_CE0CTL, 0xffffff1f},
{"EMIFA_CE1CTL", TDSP_EMIFB_CE1CTL, 0xffffff1f},
{"EMIFA_CE2CTL", TDSP_EMIFB_CE2CTL, 0x00000090},
{"EMIFA_CE3CTL", TDSP_EMIFB_CE3CTL, 0x00000090},
{"EMIFA_CE0SEC", TDSP_EMIFB_CE0SEC, 0x00000047},
{"EMIFA_CE1SEC", TDSP_EMIFB_CE1SEC, 0x00000047},
{"EMIFA_CE2SEC", TDSP_EMIFB_CE2SEC, 0x00000047},
{"EMIFA_CE3SEC", TDSP_EMIFB_CE3SEC, 0x00000047},
{NULL, -1, 0}
};
const emif_config_t emifb[] = {
{"EMIFB_GBLCTL", TDSP_EMIFB_GBLCTL, 0x0001200c},
{"EMIFB_SDCTL", TDSP_EMIFB_SDCTL, 0x63117000},
{"EMIFB_SDTIM", TDSP_EMIFB_SDTIM, 0x02000600},
{"EMIFB_CE0CTL", TDSP_EMIFB_CE0CTL, 0xffffff1f},
{"EMIFB_CE1CTL", TDSP_EMIFB_CE1CTL, 0xffffff1f},
{"EMIFB_CE2CTL", TDSP_EMIFB_CE2CTL, 0x00000090},
{"EMIFB_CE3CTL", TDSP_EMIFB_CE3CTL, 0x00000090},
{"EMIFB_CE0SEC", TDSP_EMIFB_CE0SEC, 0x00000047},
{"EMIFB_CE1SEC", TDSP_EMIFB_CE1SEC, 0x00000047},
{"EMIFB_CE2SEC", TDSP_EMIFB_CE2SEC, 0x00000047},
{"EMIFB_CE3SEC", TDSP_EMIFB_CE3SEC, 0x00000047},
{NULL, -1, 0}
};
extern struct cfdriver tdsp_cd;
/* global variable for saving current window page */
static tdsp_reg32_t dspp;
static int tdsp_is_open;
static u_int32_t tdsp_read_memory
__P((struct tdsp_softc*, tdsp_addr_t));
static void tdsp_write_memory
__P((struct tdsp_softc*, tdsp_addr_t, u_int32_t));
int tdsp_read_memory_block
__P((struct tdsp_softc*, const tdsp_addr_t, u_int8_t*, u_int32_t));
int tdsp_write_memory_block
__P((struct tdsp_softc*, const tdsp_addr_t, u_int8_t*, u_int32_t));
static void tdsp_memory_test
__P((struct tdsp_softc*, tdsp_addr_t, u_int32_t));
static tdsp_addr_t tdsp_set_page
__P((struct tdsp_softc*, tdsp_addr_t));
static int tdsp_init_emif __P((struct tdsp_softc*, const emif_config_t*));
//static void tdsp_boot __P((struct tdsp_softc*));
void tdsp_boot __P((struct tdsp_softc*));
void
tdsp_attach(struct tdsp_softc *sc)
{
bus_space_tag_t memt, iot;
bus_space_handle_t memh, ioh;
//bus_addr_t addr;
//u_int32_t src, mask, hsr, rstsrc;
int i;
memt = sc->sc_npmemt;
memh = sc->sc_npmemh;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
/* Configuration of the emif control registers */
/* EMIFA configuration */
printf("%s: configuring EMIFA\n", sc->sc_dev.dv_xname);
i = tdsp_init_emif(sc, emifa);
if (emifa[i].addr != -1) {
ERROR("%s: EMIFA is not configured.\n", sc->sc_dev.dv_xname);
}
/* EMIFB configuration */
printf("%s: configure EMIFB\n", sc->sc_dev.dv_xname);
i = tdsp_init_emif(sc, emifb);
if (emifb[i].addr != -1) {
ERROR("%s: EMIFB is not configured.\n", sc->sc_dev.dv_xname);
}
#if DIAGNOSTIC
{
/* TODO implement memory test code */
/* Test internal memory */
INFO("%s: Testing internal RAM\n", sc->sc_dev.dv_xname);
tdsp_memory_test(sc, TDSP_SRAM_BASE, TDSP_SRAM_SIZE);
/* Test external SDRAM */
INFO("%s: Testing EMIFB SDRAM\n", sc->sc_dev.dv_xname);
tdsp_memory_test(sc, TDSP_EMIFB_CE2, TDSP_EMIFB_SDRAM_SIZE);
}
#endif /* DIAGNOSTIC */
/* Clearing PCI interrupt-related registers */
/* Read PCI interrupt enable reigster(PCIIEN) */
/*
mask = bus_space_read_4(memt, memh, TDSP_PERI_PCIIEN);
DEBUGF("%s: PCIIEN = 0x%08x\n", sc->sc_dev.dv_xname, mask);
*/
/* Read other PCI interrupt related registers */
/*
src = bus_space_read_4(memt, memh, TDSP_PERI_PCIIS);
hsr = bus_space_read_4(iot, ioh, TDSP_IO_HSR);
rstsrc = bus_space_read_4(memt, memh, TDSP_PERI_RSTSRC);
DEBUGF("%s: before clearing interrupts - \n"
"\tPCIIS = 0x%08x, HSR = 0x%08x, RSTSRC = 0x%08x\n",
sc->sc_dev.dv_xname, src, hsr, rstsrc);
*/
/* Clear the registers */
/* Clear all interrupt sources */
/*
bus_space_write_4(memt, memh, TDSP_PERI_PCIIS, 0x00000bff);
*/
/* Deassert and mask out /PINTA */
bus_space_write_4(iot, ioh, TDSP_IO_HSR, 0x00000001);
/* Deassert /PINTA */
/*
bus_space_write_4(memt, memh, TDSP_PERI_RSTSRC, 0x00000010);
*/
/* Read the registers again */
/*
src = bus_space_read_4(memt, memh, TDSP_PERI_PCIIS);
hsr = bus_space_read_4(iot, ioh, TDSP_IO_HSR);
rstsrc = bus_space_read_4(memt, memh, TDSP_PERI_RSTSRC);
DEBUGF("%s: after clearing interrupts - \n"
"\tPCIIS = 0x%08x, HSR = 0x%08x, RSTSRC = 0x%08x\n",
sc->sc_dev.dv_xname, src, hsr, rstsrc);
*/
/* DEBUGF("phygeeks: DSP RAM contents @0x10000(before boot) = 0x%08x\n",
tdsp_read_memory(sc, 0x10000));
tdsp_boot(sc);
DEBUGF("phygeeks: Wait 1s...\n");
delay(1000000);
DEBUGF("phygeeks: DSP RAM contents @0x10000(after boot) = 0x%08x\n",
tdsp_read_memory(sc, 0x10000));
*/
}
int
tdspopen(dev_t dev, int ioflag, int mode, struct proc *p)
{
struct tdsp_softc *sc;
char *name;
sc = device_lookup(&tdsp_cd, TDSPUNIT(dev));
if(sc == NULL){
ERROR("NULL sc is returned: "
"cannot proceed tdspopen() anymore.\n");
return (ENXIO);
}
name = sc->sc_dev.dv_xname;
if(tdsp_is_open){
ERROR("%s: already opened.\n", name);
return (EBUSY);
}
tdsp_is_open = TRUE;
DEBUGF("%s: opened.\n", name);
return 0;
}
int
tdspclose(dev_t dev, int ioflag, int mode, struct proc *p)
{
struct tdsp_softc *sc;
char *name;
sc = device_lookup(&tdsp_cd, TDSPUNIT(dev));
if(sc == NULL){
ERROR("NULL sc is returned: "
"cannot proceed tdspclose() anymore.\n");
return (ENXIO);
}
name = sc->sc_dev.dv_xname;
if(!tdsp_is_open){
ERROR("%s: already closed.\n", sc->sc_dev.dv_xname);
return (EBADF);
}
tdsp_is_open = FALSE;
DEBUGF("%s: closed.\n", name);
return 0;
}
int
tdspioctl(dev_t dev, u_long cmd, caddr_t addr, int ioflag, struct proc *p)
{
struct tdsp_softc *sc;
char *name;
sc = device_lookup(&tdsp_cd, TDSPUNIT(dev));
if (sc == NULL){
ERROR("NULL sc is returned: "
"cannot proceed tdspioctl() anymore.\n");
return (ENXIO);
}
name = sc->sc_dev.dv_xname;
switch (cmd) {
case TDSP_RESET:
/* DSP warm reset */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TDSP_IO_HDCR,
0x00000001);
DEBUGF("%s: Reset\n", name);
return 0;
case TDSP_BOOT:
/*
* Generates a host interrupt to the DSP.
* This interrupt will take DSP CPU out of reset.
*/
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TDSP_IO_HDCR,
0x00000002);
DEBUGF("%s: Jump to address 0\n", name);
return 0;
case TDSP_SET_PAGE:
/*
* Set DSPP to the page of the requested address
* and returns the offset of the address.
*/
*(u_int32_t*)addr = tdsp_set_page(sc, *(u_int32_t*)addr);
DEBUGF("%s: Set DSPP to 0x%03x\n",
name, (*(u_int32_t*)addr) >> TDSP_PAGE_WIDTH);
return 0;
case TDSP_GET_PAGE:
*(u_int32_t*)addr = dspp;
DEBUGF("%s: DSPP is 0x%03x\n", name, dspp);
return 0;
case TDSP_DISPLAY_MEMORY:
{
int i = 0;
u_int8_t *start_addr = *(u_int8_t**)addr;
while(i < 0x100){
if(i % 16 == 0)
DEBUGF("\n0x%08x: ",
(int)(start_addr + i));
DEBUGF("%02x ", *(start_addr + i));
i++;
}
DEBUGF("\n");
}
return 0;
default:
return (ENOTTY);
}
return (ENOTTY);
}
int tdsppoll(dev, event, p)
dev_t dev;
int event;
struct proc *p;
{
return 0;
}
/*
* XXX tdspmmap() maps an area in the PCI window, not DSP memory space itself.
* Think about a method that will enforce a user not to forget the thing.
*/
paddr_t
tdspmmap(dev_t dev, off_t off, int prot)
{
struct tdsp_softc *sc;
char *name;
paddr_t paddr;
sc = device_lookup(&tdsp_cd, TDSPUNIT(dev));
if (sc == NULL){
ERROR("NULL sc is returned: "
"cannot proceed tdspmmap() anymore.\n");
return (ENXIO);
}
name = sc->sc_dev.dv_xname;
if (off >= TDSP_PMEM_MASK || off < 0){
ERROR("%s: Offset is out of range.\n", name);
return -1;
}
DEBUGF("%s: sc_pmema = 0x%08x, off = 0x%08x\n", name, sc->sc_pmema,
(int)off);
paddr = bus_space_mmap(sc->sc_pmemt, sc->sc_pmema, off, prot,
BUS_SPACE_MAP_LINEAR);
DEBUGF("%s: return value of bus_space_mmap = 0x%08x\n", name,
(u_int32_t)paddr);
return paddr;
}
int
tdspintr(void* arg)
{
struct tdsp_softc *sc = arg;
bus_space_tag_t memt, iot;
bus_space_handle_t memh, ioh;
u_int32_t src, mask, hsr, rstsrc;
memt = sc->sc_npmemt;
memh = sc->sc_npmemh;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
src = bus_space_read_4(memt, memh, TDSP_PERI_PCIIS);
mask = bus_space_read_4(memt, memh, TDSP_PERI_PCIIEN);
hsr = bus_space_read_4(iot, ioh, TDSP_IO_HSR);
rstsrc = bus_space_read_4(memt, memh, TDSP_PERI_RSTSRC);
DEBUGF("%s: interrupt - "
"PCIIS = 0x%08x, PCIIEN = 0x%08x, HSR = 0x%08x, rstsrc = 0x%08x\n",
sc->sc_dev.dv_xname, src, mask, hsr, rstsrc);
/* clear interrupt */
bus_space_write_4(memt, memh, TDSP_PERI_PCIIS, 0xffffffff);
bus_space_write_4(iot, ioh, TDSP_IO_HSR, 0xffffffff);
bus_space_write_4(memt, memh, TDSP_PERI_RSTSRC, 0x10);
return 0;
}
int tdsp_init_emif(struct tdsp_softc *sc, const emif_config_t* emif_configs)
{
int i;
bus_space_tag_t memt = sc->sc_npmemt;
bus_space_handle_t memh = sc->sc_npmemh;
bus_addr_t addr;
for (i = 0; emif_configs[i].addr != -1; i++) {
/* Set EMIF registers */
addr = (emif_configs[i].addr);
bus_space_write_4(memt, memh, addr, emif_configs[i].val);
#if DIAGNOSTIC
{
u_int32_t val;
/* Wait at least 1 ms to pass the transient state */
delay(1);
/* Read the values of the registers back */
val = bus_space_read_4(memt, memh, addr);
DEBUGF("%s: %s\t- 0x%08x written, 0x%08x read\n",
sc->sc_dev.dv_xname, emif_configs[i].name,
emif_configs[i].val, val);
}
#endif /* DIAGNOSTIC */
}
return i;
}
/*
* Load boot code to DSP memory and boot DSP CPU
* XXX This should be removed in future works
*/
void tdsp_boot(struct tdsp_softc *sc)
{
int i = 0;
int size, addr;
int sizeof_talker_code = sizeof(talker_code);
INFO("%s: Load boot code\n", sc->sc_dev.dv_xname);
/* Loop until all the code are loaded */
while(i < sizeof_talker_code)
{
/*
* Each section starts with the size of it
* and the address to load it
*/
u_int32_t *section = (u_int32_t*)(talker_code + i);
/* Size of the section is stored in little endian */
size = letobe_32(section[0]);
/* Address of the section is stored in little endian */
addr = letobe_32(section[1]);
/* Code of a section starts after 8 bytes */
i += 8;
tdsp_write_memory_block(sc, addr, talker_code + i, size);
INFO("%s: Boot code section of size 0x%x loaded at 0x%08x\n",
sc->sc_dev.dv_xname, size, addr);
/* Now jump to another section */
i += size;
}
/* Take DSP core out of reset */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TDSP_IO_HDCR, 0x00000002);
}
static tdsp_addr_t tdsp_set_page(struct tdsp_softc* sc, tdsp_addr_t addr)
{
/* calculate the page of the requested address */
tdsp_reg32_t page = addr >> TDSP_PAGE_WIDTH;
/* set the value of DSPP as the calcuated one if different */
if (dspp != page) {
dspp = page;
bus_space_write_4(sc->sc_iot, sc->sc_ioh,
TDSP_IO_DSPP, page);
}
/* return the offset */
return (addr & TDSP_PMEM_MASK);
}
/*
* Read 4 bytes from the designated address
* and return byte-ordering swapped value
*/
u_int32_t tdsp_read_memory(struct tdsp_softc* sc, tdsp_addr_t addr)
{
tdsp_reg32_t save;
tdsp_addr_t offset;
le32_t ret;
/* save DSPP to a temporary variable to restore later */
save = dspp;
/* set DSPP to the requested page and get the offset */
offset = tdsp_set_page(sc, addr);
/* read the value of the requested address */
ret = bus_space_read_4(sc->sc_pmemt, sc->sc_pmemh, offset);
/* restore DSPP */
tdsp_set_page(sc, save << TDSP_PAGE_WIDTH);
/* change the byte ordering and return */
return ret;
}
/*
* Write 4 bytes of byte-ordering swapped value to the designated address
*/
void tdsp_write_memory(struct tdsp_softc* sc, tdsp_addr_t addr, u_int32_t val)
{
tdsp_reg32_t save;
tdsp_addr_t offset;
/* save DSPP to a temporary variable to restore later */
save = dspp;
/* set DSPP to the requested page and get the offset */
offset = tdsp_set_page(sc, addr);
/* change the byte ordering and write to the requested address */
bus_space_write_4(sc->sc_pmemt, sc->sc_pmemh, offset, val);
/* restore dspp */
tdsp_set_page(sc, save << TDSP_PAGE_WIDTH);
}
/*
* Read a block of DSP memory to CPU memory.
* Return the number of bytes read.
*/
int tdsp_read_memory_block(struct tdsp_softc *sc, const tdsp_addr_t tdsp_addr,
u_int8_t *datap, u_int32_t count)
{
bus_size_t offset;
/* save DSPP to restore later */
tdsp_reg32_t save = dspp;
/* check if the size of the chunk is valid */
if((tdsp_addr >> TDSP_PAGE_WIDTH) !=
((tdsp_addr + count - 1) >> TDSP_PAGE_WIDTH)){
ERROR("%s: Memory block should be within a 4MB page.\n",
sc->sc_dev.dv_xname);
return 0;
}
offset = tdsp_set_page(sc, tdsp_addr);
bus_space_read_region_1(sc->sc_pmemt, sc->sc_pmemh, offset,
datap, count);
/* restore DSPP */
tdsp_set_page(sc, save << TDSP_PAGE_WIDTH);
return count;
}
/*
* Write a block of CPU memory to DSP memory.
* Return the number of bytes written.
*/
int tdsp_write_memory_block(struct tdsp_softc *sc, const tdsp_addr_t tdsp_addr,
u_int8_t *datap, u_int32_t count)
{
bus_size_t offset;
/* save DSPP to restore later */
tdsp_reg32_t save = dspp;
/* check if the size of the chunk is valid */
if((tdsp_addr >> TDSP_PAGE_WIDTH) !=
((tdsp_addr + count - 1) >> TDSP_PAGE_WIDTH)){
ERROR("%s: Memory block should be within a 4MB block.\n",
sc->sc_dev.dv_xname);
return 0;
}
offset = tdsp_set_page(sc, tdsp_addr);
bus_space_write_region_1(sc->sc_pmemt, sc->sc_pmemh, offset,
datap, count);
/*
{
int i;
for(i = 0; i < count; i++){
bus_space_write_1(sc->sc_pmemt, sc->sc_pmemh,
offset + i, *(datap + i));
}
}
*/
/* restore DSPP */
tdsp_set_page(sc, save << TDSP_PAGE_WIDTH);
return count;
}
void tdsp_memory_test(struct tdsp_softc* sc, tdsp_addr_t start_addr,
u_int32_t size)
{
int addr;
int step = 4;
INFO("%s: Test memory from 0x%08x to 0x%08x",
sc->sc_dev.dv_xname, start_addr, start_addr + size - 1);
for(addr = start_addr; addr < start_addr + size; addr += step){
if(addr % (size >> 4) == 0) INFO(".");
tdsp_write_memory(sc, addr, addr);
if(tdsp_read_memory(sc, addr) != addr){
ERROR("***Failed at 0x%08x***\n", addr);
return;
}
}
INFO("OK.\n");
}
----
and test application program.
----
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "../../sys/arch/sandpoint/xepro/tdsp_ioctl.h"
typedef struct mmapinfo {
void *addr;
u_int32_t page;
u_int32_t offset;
u_int32_t len;
} mmapinfo_t;
int print_memory(mmapinfo_t*);
#define printf(format, args...) \
{ \
fprintf(stdout, format, ##args); \
}
#define BASE_ADDRESS 0x80800000
int
main(int argc, char* argv[])
{
int tdsph;
u_int32_t start_addr;
u_int32_t end_addr;
u_int8_t* addr;
mmapinfo_t sram;
start_addr = strtoul(argv[1], NULL, 16);
end_addr = strtoul(argv[2], NULL, 16);
if(argc < 3){
printf("Input start address and end address as arguments.\n");
return -1;
}
tdsph = open("/dev/tdsp", O_RDWR, 0);
if(tdsph == -1){
perror("open error");
return -1;
}
sram.len = end_addr - start_addr + 1;
printf("sram.len = 0x%x\n", sram.len);
sram.offset = start_addr;
if(ioctl(tdsph, TDSP_SET_PAGE, &sram.offset) == -1){
perror("ioctl TDSP_SET_PAGE error");
return -1;
}
printf("sram.offset = 0x%x\n", sram.offset);
if(ioctl(tdsph, TDSP_GET_PAGE, &sram.page) == -1){
perror("ioctl TDSP_GET_PAGE error");
return -1;
}
printf("sram.page = 0x%x\n", sram.page);
sram.addr = mmap(0, sram.len, PROT_READ, MAP_SHARED, tdsph,
(off_t)sram.offset);
if(sram.addr == MAP_FAILED){
perror("mmap error");
return -1;
}
printf("sram.addr = 0x%08x\n", (u_int32_t)sram.addr);
print_memory(&sram);
*((u_int32_t*)sram.addr) = 0x12345678;
addr = (u_int8_t*)((BASE_ADDRESS + start_addr) % (1 << 22));
if(ioctl(tdsph, TDSP_DISPLAY_MEMORY, &addr) == -1){
perror("ioctl TDSP_DISPLAY_MEMORY error");
return -1;
}
close(tdsph);
return 0;
}
int
print_memory(mmapinfo_t *p_memory)
{
int i = 0;
u_int32_t start_addr = (p_memory->page << 22) + p_memory->offset;
while(i < p_memory->len){
if(i % 16 == 0)
printf("\n0x%08x: ", start_addr + i);
printf("%02x ", *((u_int8_t*)p_memory->addr + i));
i++;
}
printf("\n");
return 0;
}
----