From 2c5b3625a7226b7ebb91224b1e4441a80eefb404 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 23 Jan 2013 11:54:23 -0300 Subject: [PATCH] ubb-la/: data capture via UBB and MSC+DMA (WIP) --- ubb-la/Makefile | 34 +++++++ ubb-la/ubb-la.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 ubb-la/Makefile create mode 100644 ubb-la/ubb-la.c diff --git a/ubb-la/Makefile b/ubb-la/Makefile new file mode 100644 index 0000000..5b577fe --- /dev/null +++ b/ubb-la/Makefile @@ -0,0 +1,34 @@ +# +# ubb-la/Makefile - Build the UBB logic analyzer +# +# Written 2013 by Werner Almesberger +# Copyright 2013 Werner Almesberger +# +# 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. +# + +CC = mipsel-openwrt-linux-gcc +CFLAGS = -g -Wall -O9 -I../libubb/include +LDFLAGS = +LDLIBS = -L../libubb -lubb -lm -lrt + +MAIN = ubb-la +OBJS = ubb-la.o + +.PHONY: all static clean spotless + +all: $(MAIN) + +static: + $(MAKE) LDFLAGS=-static + +$(MAIN): $(OBJS) + +clean: + rm -f $(OBJS) + +spotless: clean + rm -f $(MAIN) diff --git a/ubb-la/ubb-la.c b/ubb-la/ubb-la.c new file mode 100644 index 0000000..18331f7 --- /dev/null +++ b/ubb-la/ubb-la.c @@ -0,0 +1,232 @@ +/* + * ubb-la.c - UBB logic analyzer + * + * Written 2013 by Werner Almesberger + * Copyright 2013 Werner Almesberger + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define DMA 5 + + +/* ----- Enable/disable interrupts ----------------------------------------- */ + + +static uint32_t old_icmr; + + +static void disable_interrupts(void) +{ + old_icmr = ICMR; + ICMSR = 0xffffffff; +} + + +static void enable_interrupts(void) +{ + ICMCR = ~old_icmr; +} + + +/* ----- DMA control ------------------------------------------------------- */ + + +static uint32_t old_dmac; + + +static void dma_stop(void) +{ + DCS(DMA) = + DCS_TT | /* Transfer terminated */ + DCS_HLT; /* DMA halt */ + DCS(DMA) = 0; /* reset DMA channel */ +} + + +static void dma_init(void) +{ + old_dmac = DMAC; + + DMAC = DMAC_DMAE; /* activate the DMA controller (in case it's off) */ + dma_stop(); + + DCM(DMA) = + DCM_DAI | /* destination address increment */ + (DCM_TSZ_32BYTE << DCM_TSZ_SHIFT); + /* transfer size is 32 bytes */ + DRT(DMA) = DRT_MSC_RX; /* MSC receive-fifo-full transfer request */ +} + + +static void dma_cleanup(void) +{ + DMAC = old_dmac; + dma_stop(); +} + + +static void dma_setup(unsigned long buf, int nibbles) +{ + assert(!(nibbles & 63)); + + DCS(DMA) = DCS_NDES; /* no-descriptor transfer */ + DSA(DMA) = REG_PADDR(MSC_RXFIFO); /* source */ + DTA(DMA) = buf; /* destination */ + DTC(DMA) = nibbles >> 6; /* 32 bytes per transfer */ +} + + +static void wait_dma_done(void) +{ + while (!(DCS(DMA) & DCS_TT)); +} + + +/* ----- MMC control ------------------------------------------------------- */ + + +static void xfer(unsigned long buf, int nibbles) +{ + dma_init(); + dma_setup(buf, nibbles); + + MSC_STRPCL = MSC_STRPCRL_START_CLOCK; /* start the bus clock */ + MSC_RESTO = MSC_RESTO_MASK; /* maximum response time-out */ + MSC_RDTO = MSC_RDTO_MASK; + MSC_BLKLEN = nibbles >> 1; + + MSC_CMDAT = + MSC_CMDAT_BUS_WIDTH_4 << MSC_CMDAT_BUS_WIDTH_SHIFT | + MSC_CMDAT_DMA_EN | /* DMA */ + MSC_CMDAT_DATA_EN | /* with data transfer */ + MSC_CMDAT_RESPONSE_FORMAT_NONE; /* no response required */ + + MSC_STRPCL = MSC_STRPCRL_START_OP; + + while (MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY); + + IN(UBB_CMD); + + disable_interrupts(); + + while (!(PDPIN & UBB_DAT1)); + +// sleep(1); /* @@@ wait here for trigger */ + + DCS(DMA) = + DCS_NDES | /* no descriptor */ + DCS_CTE; /* enable channel */ + + enable_interrupts(); + + wait_dma_done(); + +printf("MSC_STAT = %08x\n", MSC_STAT); + + dma_cleanup(); + +} + + +static void do_buf(int nibbles) +{ + uint8_t *buf = physmem_malloc(4095); + struct physmem_vec vec; + int n, i; + uint8_t v, last = 0xff; + int count = 0; + + if (mlockall(MCL_CURRENT | MCL_FUTURE)) { + perror("mlockall"); + exit(1); + } + + memset(buf, 0, 4095); + physmem_flush(buf, 4095); + + n = physmem_xlat((void *) buf, nibbles >> 1, &vec, 1); + if (n != 1) { + fprintf(stderr, "physmem_xlat_vec: expected 1, got %d\n", n); + exit(1); + } + xfer(vec.addr, nibbles); + + for (i = 0; i != nibbles; i++) { + v = (buf[i >> 1] >> (4*(~i & 1))) & 0xf; + if (v == last) { + count++; + } else { + switch (count) { + case 0: + break; + case 1: + printf("%X", last); + break; + default: + printf("%X{%d}", last, count); + break; + } + last = v; + count = 1; + } + } + if (count == 1) + printf("%X\n", last); + else + printf("%X{%d}\n", last, count); +} + + +static void frequency(struct mmcclk *clk, int hz) +{ + struct mmcclk mmc; + + mmcclk_first(&mmc, 0); + *clk = mmc; + while (mmcclk_next(&mmc)) + if (fabs(clk->bus_clk_hz-hz) > fabs(mmc.bus_clk_hz-hz)) + *clk = mmc; +} + + +int main(int argc, char **argv) +{ + struct mmcclk clk; + + ubb_open(UBB_ALL); + PDFUNS = UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3; + PDFUNS = UBB_CLK; + OUT(UBB_CMD); + CLR(UBB_CMD); + PDFUNC = UBB_CMD; + + frequency(&clk, atoi(argv[1])); + printf("bus %g MHz (MSC %g MHz)\n", clk.bus_clk_hz/1e6, + clk.sys_clk_hz/(clk.clkdiv+1.0)/1e6); + mmcclk_start(&clk); + + do_buf(6400); + + mmcclk_stop(); + ubb_close(UBB_ALL); + + return 0; +}