diff --git a/libubb/include/ubb/mmcclk.h b/libubb/include/ubb/mmcclk.h index 8762e90..ad90ea3 100644 --- a/libubb/include/ubb/mmcclk.h +++ b/libubb/include/ubb/mmcclk.h @@ -19,15 +19,34 @@ #define BEN_PLL_CLK_HZ 336000000 +/* + * By default (flags = 0), only clocks that can be used with any mode of + * operation will be generated. The following flags also include clocks ... + */ + +#define MMCCLK_FLAG_RD_ONLY (1 << 0) /* not suitable for writing */ +#define MMCCLK_FLAG_WR_ONLY (1 << 1) /* not suitable for reading */ +#define MMCCLK_FLAG_INTERNAL (1 << 2) /* not suitable for bus use */ +#define MMCCLK_FLAG_UNSAFE (1 << 3) /* that may hang the MSC */ +#define MMCCLK_FLAG_ALL (1 << 4) /* that will hang the MSC */ + +/* + * For now, only MMCCLK_FLAG_UNSAFE and MMCCLK_FLAG_ALL are implemented, but + * further research may also reveal limits that depend on the type of + * operation. + */ + + 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 */ + unsigned flags; }; -void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz); +void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz, unsigned flags); int mmcclk_next(struct mmcclk *dsc); void mmcclk_start(struct mmcclk *dsc); diff --git a/libubb/mmcclk.c b/libubb/mmcclk.c index 856ed24..78970ac 100644 --- a/libubb/mmcclk.c +++ b/libubb/mmcclk.c @@ -27,23 +27,30 @@ * Some Bens still work fine at 84 MHz. */ -#define BUS_LIMIT_MHZ 56 +#define BUS_SAFE_MHZ 56 /* always works */ +#define BUS_UNSAFE_MHZ 84 /* some devices don't like this */ 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; + if (dsc->flags & MMCCLK_FLAG_ALL) + return 1; + if ((dsc->flags & MMCCLK_FLAG_UNSAFE) && + dsc->bus_clk_hz <= BUS_UNSAFE_MHZ*1000000) + return 1; + return dsc->bus_clk_hz <= BUS_SAFE_MHZ*1000000; } -void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz) +void mmcclk_first(struct mmcclk *dsc, int sys_clk_hz, unsigned flags) { if (sys_clk_hz) dsc->sys_clk_hz = sys_clk_hz; else dsc->sys_clk_hz = (CPCCR >> 21) & 1 ? BEN_PLL_CLK_HZ : BEN_PLL_CLK_HZ/2; + dsc->flags = flags; dsc->clkdiv = dsc->clkrt = 0; if (calculate_clock(dsc)) return;