clk: rockchip: mmc: add mmc set and get phase

add mmc set and get phase for rk3128\rk3328\rk3368

Change-Id: Ic8d7764391165f28c54721c4af218f8623b2f3a7
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
This commit is contained in:
Elaine Zhang 2018-09-12 09:49:28 +08:00 committed by Jianhong Chen
parent 77745e86fd
commit aa8c298733
3 changed files with 393 additions and 0 deletions

View File

@ -588,9 +588,140 @@ static ulong rk3128_clk_set_rate(struct clk *clk, ulong rate)
return ret;
}
#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
#define ROCKCHIP_MMC_DEGREE_MASK 0x3
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
#define PSECS_PER_SEC 1000000000000LL
/*
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
int rk3128_mmc_get_phase(struct clk *clk)
{
struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3128_cru *cru = priv->cru;
u32 raw_value, delay_num;
u16 degrees = 0;
ulong rate;
rate = rk3128_clk_get_rate(clk);
if (rate < 0)
return rate;
if (clk->id == SCLK_EMMC_SAMPLE)
raw_value = readl(&cru->cru_emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
raw_value = readl(&cru->cru_sdmmc_con[1]);
else
raw_value = readl(&cru->cru_sdio_con[1]);
raw_value >>= 1;
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
/* degrees/delaynum * 10000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
36 * (rate / 1000000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
}
return degrees % 360;
}
int rk3128_mmc_set_phase(struct clk *clk, u32 degrees)
{
struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3128_cru *cru = priv->cru;
u8 nineties, remainder, delay_num;
u32 raw_value, delay;
ulong rate;
rate = rk3128_clk_get_rate(clk);
if (rate < 0)
return rate;
nineties = degrees / 90;
remainder = (degrees % 90);
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder;
delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8)min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
raw_value |= nineties;
raw_value <<= 1;
if (clk->id == SCLK_EMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
else
writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]);
debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
degrees, delay_num, raw_value, rk3128_mmc_get_phase(clk));
return 0;
}
static int rk3128_clk_get_phase(struct clk *clk)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO_SAMPLE:
ret = rk3128_mmc_get_phase(clk);
break;
default:
return -ENOENT;
}
return ret;
}
static int rk3128_clk_set_phase(struct clk *clk, int degrees)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO_SAMPLE:
ret = rk3128_mmc_set_phase(clk, degrees);
break;
default:
return -ENOENT;
}
return ret;
}
static struct clk_ops rk3128_clk_ops = {
.get_rate = rk3128_clk_get_rate,
.set_rate = rk3128_clk_set_rate,
.get_phase = rk3128_clk_get_phase,
.set_phase = rk3128_clk_set_phase,
};
static int rk3128_clk_ofdata_to_platdata(struct udevice *dev)

View File

@ -965,10 +965,141 @@ static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent)
return -ENOENT;
}
#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
#define ROCKCHIP_MMC_DEGREE_MASK 0x3
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
#define PSECS_PER_SEC 1000000000000LL
/*
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
int rk3328_mmc_get_phase(struct clk *clk)
{
struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3328_cru *cru = priv->cru;
u32 raw_value, delay_num;
u16 degrees = 0;
ulong rate;
rate = rk3328_clk_get_rate(clk);
if (rate < 0)
return rate;
if (clk->id == SCLK_EMMC_SAMPLE)
raw_value = readl(&cru->emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
raw_value = readl(&cru->sdmmc_con[1]);
else
raw_value = readl(&cru->sdio_con[1]);
raw_value >>= 1;
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
/* degrees/delaynum * 10000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
36 * (rate / 1000000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
}
return degrees % 360;
}
int rk3328_mmc_set_phase(struct clk *clk, u32 degrees)
{
struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3328_cru *cru = priv->cru;
u8 nineties, remainder, delay_num;
u32 raw_value, delay;
ulong rate;
rate = rk3328_clk_get_rate(clk);
if (rate < 0)
return rate;
nineties = degrees / 90;
remainder = (degrees % 90);
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder;
delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8)min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
raw_value |= nineties;
raw_value <<= 1;
if (clk->id == SCLK_EMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
else
writel(raw_value | 0xffff0000, &cru->sdio_con[1]);
debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
degrees, delay_num, raw_value, rk3328_mmc_get_phase(clk));
return 0;
}
static int rk3328_clk_get_phase(struct clk *clk)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO_SAMPLE:
ret = rk3328_mmc_get_phase(clk);
break;
default:
return -ENOENT;
}
return ret;
}
static int rk3328_clk_set_phase(struct clk *clk, int degrees)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO_SAMPLE:
ret = rk3328_mmc_set_phase(clk, degrees);
break;
default:
return -ENOENT;
}
return ret;
}
static struct clk_ops rk3328_clk_ops = {
.get_rate = rk3328_clk_get_rate,
.set_rate = rk3328_clk_set_rate,
.set_parent = rk3328_clk_set_parent,
.get_phase = rk3328_clk_get_phase,
.set_phase = rk3328_clk_set_phase,
};
static void rkclk_init(struct rk3328_clk_priv *priv)

View File

@ -1020,9 +1020,140 @@ static int __maybe_unused rk3368_clk_set_parent(struct clk *clk, struct clk *par
return -ENOENT;
}
#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
#define ROCKCHIP_MMC_DEGREE_MASK 0x3
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
#define PSECS_PER_SEC 1000000000000LL
/*
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
int rk3368_mmc_get_phase(struct clk *clk)
{
struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3368_cru *cru = priv->cru;
u32 raw_value, delay_num;
u16 degrees = 0;
ulong rate;
rate = rk3368_clk_get_rate(clk);
if (rate < 0)
return rate;
if (clk->id == SCLK_EMMC_SAMPLE)
raw_value = readl(&cru->emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
raw_value = readl(&cru->sdmmc_con[1]);
else
raw_value = readl(&cru->sdio0_con[1]);
raw_value >>= 1;
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
/* degrees/delaynum * 10000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
36 * (rate / 1000000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
}
return degrees % 360;
}
int rk3368_mmc_set_phase(struct clk *clk, u32 degrees)
{
struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3368_cru *cru = priv->cru;
u8 nineties, remainder, delay_num;
u32 raw_value, delay;
ulong rate;
rate = rk3368_clk_get_rate(clk);
if (rate < 0)
return rate;
nineties = degrees / 90;
remainder = (degrees % 90);
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder;
delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8)min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
raw_value |= nineties;
raw_value <<= 1;
if (clk->id == SCLK_EMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
else if (clk->id == SCLK_SDMMC_SAMPLE)
writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
else
writel(raw_value | 0xffff0000, &cru->sdio0_con[1]);
debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
degrees, delay_num, raw_value, rk3368_mmc_get_phase(clk));
return 0;
}
static int rk3368_clk_get_phase(struct clk *clk)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO0_SAMPLE:
ret = rk3368_mmc_get_phase(clk);
break;
default:
return -ENOENT;
}
return ret;
}
static int rk3368_clk_set_phase(struct clk *clk, int degrees)
{
int ret;
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case SCLK_EMMC_SAMPLE:
case SCLK_SDMMC_SAMPLE:
case SCLK_SDIO0_SAMPLE:
ret = rk3368_mmc_set_phase(clk, degrees);
break;
default:
return -ENOENT;
}
return ret;
}
static struct clk_ops rk3368_clk_ops = {
.get_rate = rk3368_clk_get_rate,
.set_rate = rk3368_clk_set_rate,
.get_phase = rk3368_clk_get_phase,
.set_phase = rk3368_clk_set_phase,
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
.set_parent = rk3368_clk_set_parent,
#endif