diff --git a/libubb/Makefile b/libubb/Makefile index bd9c71d..a4be822 100644 --- a/libubb/Makefile +++ b/libubb/Makefile @@ -20,8 +20,8 @@ LIB = libubb.a SHLIB = libubb.so LIBVERSION = 0.0.0 -OBJS = ubb.o swuart.o -HDRS = ubb/ubb.h ubb/regbase.h ubb/regs4740.h ubb/swuart.h +OBJS = ubb.o swuart.o mmcclk.o +HDRS = ubb/ubb.h ubb/regbase.h ubb/regs4740.h ubb/swuart.h ubb/mmcclk.h .PHONY: all clean spotless diff --git a/libubb/include/ubb/mmcclk.h b/libubb/include/ubb/mmcclk.h new file mode 100644 index 0000000..289a887 --- /dev/null +++ b/libubb/include/ubb/mmcclk.h @@ -0,0 +1,36 @@ +/* + * include/ubb/mmcclk.h - Calculate MMC bus clock speed + * + * 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. + */ + +#ifndef UBB_MMCCLK_H +#define UBB_MMCCLK_H + +#include + + +#define BEN_SYS_CLK_HZ 336000000 + + +struct mmcclk { + int sys_clk_hz; /* system clock speed in Hz */ + double bus_clk_hz; /* MMC bus clock in Hz */ + uint32_t clkdiv; /* MSC controller clock */ + uint32_t clkrt; /* bus clock divider */ +}; + + +void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz); +int mmcclk_next(struct mmcclk *dsc); + +void mmcclk_start(struct mmcclk *dsc); +void mmcclk_stop(void); + +#endif /* !UBB_MMCCLK_H */ diff --git a/libubb/mmcclk.c b/libubb/mmcclk.c new file mode 100644 index 0000000..b84fe59 --- /dev/null +++ b/libubb/mmcclk.c @@ -0,0 +1,67 @@ +/* + * libubb/mmcclk.c - Calculate MMC bus clock speed + * + * 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 + + +#define MSCCDR_MAX 32 +#define CLKRT_MAX 8 + +#define BUS_LIMIT_MHZ 56 /* nominally, the limit is 20 MHz */ + + +static int calculate_clock(struct mmcclk *dsc) +{ + dsc->bus_clk_hz = dsc->sys_clk_hz/(dsc->clkdiv+1.0)/(1 << dsc->clkrt); + return dsc->bus_clk_hz <= BUS_LIMIT_MHZ*1000000; +} + + +void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz) +{ + dsc->sys_clk_hz = sys_clk_hz ? sys_clk_hz : BEN_SYS_CLK_HZ; + dsc->clkdiv = dsc->clkrt = 0; + if (calculate_clock(dsc)) + return; + mmcclk_next(dsc); +} + + +int mmcclk_next(struct mmcclk *dsc) +{ + while (1) { + if (++dsc->clkdiv == MSCCDR_MAX) { + dsc->clkdiv = 0; + if (++dsc->clkrt == CLKRT_MAX) + return 0; + } + if (calculate_clock(dsc)) + return 1; + } +} + + +void mmcclk_start(struct mmcclk *dsc) +{ + MSCCDR = dsc->clkdiv; /* set controller clock */ + CLKGR &= ~(1 << 7); /* enable MSC clock */ + MSC_CLKRT = dsc->clkrt; /* set bus clock */ + MSC_STRPCL = 2; /* start MMC bus clock output */ +} + + +void mmcclk_stop(void) +{ + MSC_STRPCL = 1; /* stop MMC bus clock output */ +}