/* * 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) { 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->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 */ }