Ejemplo n.º 1
0
void mshci_hi_set_ios(struct mshci_host *ms_host, struct mmc_ios *ios)
{
	struct himci_host * hi_host = (struct himci_host *)(ms_host->private);
	int ret = -1;

	hi_host_trace(HIMCI_TRACE_GEN_API, "++");

	himci_assert(ios);
	himci_assert(hi_host);

	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->power_mode = %d ", ios->power_mode);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->clock = %d ", ios->clock);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->bus_width = %d ", ios->bus_width);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->timing = %d ", ios->timing);

	/* process power */
	if (hi_host->old_power_mode != ios->power_mode) {
		switch (ios->power_mode) {
		case MMC_POWER_OFF:
		    hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to lowpower");
		    if (hi_host->vcc) {
				regulator_disable(hi_host->vcc);
		    }
			if (hi_host->signal_vcc) {
				regulator_disable(hi_host->signal_vcc);
				regulator_set_mode(hi_host->signal_vcc, REGULATOR_MODE_IDLE);
		    }

		    ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
		    if (ret) {
				himci_error("failed to blockmux_set");
		    }

			break;
		case MMC_POWER_UP:
		    hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to normal");

		    ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
		    if (ret) {
				himci_error("failed to blockmux_set");
		    }

		    if (hi_host->vcc) {
				ret = regulator_set_voltage(hi_host->vcc, 2850000, 2850000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}

				ret = regulator_enable(hi_host->vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
		    }
			if (hi_host->signal_vcc) {
				ret = regulator_set_voltage(hi_host->signal_vcc, 2600000, 2600000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}
				regulator_set_mode(hi_host->signal_vcc, REGULATOR_MODE_NORMAL);
				ret = regulator_enable(hi_host->signal_vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}

		    }
			break;
		case MMC_POWER_ON:
			break;
		default:
			himci_error("unknown power supply mode");
			break;
		}
		hi_host->old_power_mode = ios->power_mode;
	}

	/* process timing */
	if (hi_host->old_timing != ios->timing) {

		hi_host->old_timing = ios->timing;

		if ( get_chipid() == DI_CHIP_ID ) {
			mshci_hi_update_timing(ms_host, 0);

			switch (ios->timing) {
			case MMC_TIMING_LEGACY:
				if (hi_host->pdev->id == 1) {
					/* 2 division, 40M */
					writel((0x1<<6) | (0x7<<22),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 40*1000*1000;
					ms_host->clock++;
				} else if (hi_host->pdev->id == 0) {
					/* 2 division, 40M */
					writel((0x0<<5) | (0x1<<21),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 40*1000*1000;
					ms_host->clock++;
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_LEGACY");
				break;
			case MMC_TIMING_UHS_DDR50:
				if (hi_host->pdev->id == 1) {
					/* 1 division, 80M */
					writel((0x0<<6) | (0x7<<22),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 80*1000*1000;
					ms_host->clock++;
				} else {
#if 0
					/*
					 * m53980:
					 * debug purpose.
					 * change clock via sctrl configuration
					 */
					printk("clk div a:0x%x\n", readl(IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2));
					writel((0x7)|(0xF<<16), IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					printk("clk div b:0x%x\n", readl(IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2));
#endif
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_UHS_DDR50");
				break;
			case MMC_TIMING_UHS_SDR50:
				if (hi_host->pdev->id == 0) {
					writel((0x1<<5) | (0x1<<21),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 80*1000*1000;
					ms_host->clock++;
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_UHS_SDR50");
				break;
			default:
				break;
			}
		} else {
			ret = clk_set_rate(hi_host->pclk,hi_host->init_tuning_config[0 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]);
			if (ret) {
				himci_error("failed to clk_set_rate");
			}
			hi_host->tuning_init_sample =
					(hi_host->init_tuning_config[3 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM] +
					hi_host->init_tuning_config[4 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]) / 2;
			mshci_hi_set_timing(hi_host,
				hi_host->tuning_init_sample,
				hi_host->init_tuning_config[2 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM],
				hi_host->init_tuning_config[1 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]);

			ms_host->max_clk = hi_host->init_tuning_config[5 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM];

			ms_host->clock++;
		}
	}

	hi_host_trace(HIMCI_TRACE_GEN_API, "--");
}
Ejemplo n.º 2
0
/*			-1 -- Tuning failed. Maybe slow down the clock and call this function again */
static int mshci_hi_tuning_find_condition(struct mshci_host *ms_host)
{
	struct himci_host *hi_host;
	int sample_min, sample_max;
	/*int begin, end;*/
	int i, j;
	int ret = 0;
	int mask,mask_lenth;

	hi_host = mshci_priv(ms_host);

	if (hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM] ==
		hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) {
		hi_host->tuning_init_sample =
			(hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM] +
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) / 2;
		mshci_hi_set_timing(hi_host, hi_host->tuning_init_sample, -1, -1);
		hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
			"no need tuning: timing is %d, tuning sample = %d",
			ms_host->mmc->ios.timing, hi_host->tuning_init_sample);
		return 0;
	}
	if (-1 == hi_host->tuning_current_sample) {

		mshci_hi_tuning_clear_flags(hi_host);

		/* set the first sam del as the min_sam_del */
		hi_host->tuning_current_sample =
			hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];
		/* a trick for next "++" */
		hi_host->tuning_current_sample--;
	}

	if (hi_host->tuning_current_sample >=
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) {
		/* tuning finish, select the best sam_del */

		/* set sam del to -1, for next tuning */
		hi_host->tuning_current_sample = -1;

		sample_min =
			hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];
		sample_max =
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];

#if 0
		begin = -1;
		end = -1;
		for (i = sample_min; i <= sample_max; i++) {
			if (-1 == begin) {
				/* no begin, find begin */
				if (mshci_hi_tuning_get_flags(hi_host, i)) {
					begin = i;
				} else {
					continue;
				}
			} else if (-1 == end) {
				/* no end, find end */
				if (mshci_hi_tuning_get_flags(hi_host, i)) {
					if (i == sample_max) {
						end = sample_max;
					} else {
						continue;
					}
				} else {
					end = i - 1;
				}
			} else {
				/* has begin & end, break */
				break;
			}
		}

		if (-1 == begin) {
			hi_host->tuning_init_sample = (sample_min + sample_max) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
				"tuning err: no good sam_del, timing is %d, tuning_flag = 0x%x",
				ms_host->mmc->ios.timing, hi_host->tuning_sample_flag);
			ret = -1;
		} else if (-1 == end) {
			hi_host->tuning_init_sample = (begin + sample_max) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
					"tuning err: no end! arithmetic error, timing is %d, begin = %d; tuning_flag = 0x%x",
					ms_host->mmc->ios.timing, begin, hi_host->tuning_sample_flag);
			ret = -1;
		} else {
			hi_host->tuning_init_sample = (begin + end) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
				"tuning OK: timing is %d, tuning sample = %d, tuning_flag = 0x%x",
				ms_host->mmc->ios.timing, hi_host->tuning_init_sample, hi_host->tuning_sample_flag);
			ret = 0;
		}
#else
		hi_host->tuning_init_sample = -1;
		for (mask_lenth = (((sample_max - sample_min) >> 1) << 1) + 1;
			mask_lenth >= 1; mask_lenth -= 2) {

				mask = (1 << mask_lenth) - 1;
				for (i = (sample_min + sample_max - mask_lenth + 1) / 2, j = 1;
					(i <= sample_max - mask_lenth + 1) && (i >= sample_min);
					i = ((sample_min + sample_max - mask_lenth + 1) / 2) + ((j % 2) ? -1 : 1) * (j / 2)) {
					if ((hi_host->tuning_sample_flag & (mask << i)) == (mask << i)) {
						hi_host->tuning_init_sample = i + mask_lenth / 2 ;
						break;
					}

					j++;
				}

				if (hi_host->tuning_init_sample != -1) {
					hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
						"tuning OK: timing is %d, tuning sample = %d, tuning_flag = 0x%x",
						ms_host->mmc->ios.timing, hi_host->tuning_init_sample, hi_host->tuning_sample_flag);
					ret = 0;
					break;
				}
		}

		if (-1 == hi_host->tuning_init_sample) {
			hi_host->tuning_init_sample = (sample_min + sample_max) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
				"tuning err: no good sam_del, timing is %d, tuning_flag = 0x%x",
				ms_host->mmc->ios.timing, hi_host->tuning_sample_flag);
			ret = -1;
		}
#endif

		mshci_hi_set_timing(hi_host, hi_host->tuning_init_sample, -1, -1);
		return ret;
	} else {
Ejemplo n.º 3
0
/*			-1 -- Tuning failed. Maybe slow down the clock and call this function again */
static int mshci_hi_tuning_find_condition(struct mshci_host *ms_host)
{
	struct himci_host *hi_host;
	struct mmc_host *mmc;
	int sample_min, sample_max;
	/*int begin, end;*/
	int i, j;
	int ret;
	int mask,mask_lenth;

	hi_host = mshci_priv(ms_host);
	mmc = ms_host->mmc;

	if (hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM] ==
		hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) {
		hi_host->tuning_init_sample =
			(hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM] +
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) / 2;
		mshci_hi_set_timing(hi_host, hi_host->tuning_init_sample, -1, -1);
		hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
			"no need tuning: timing is %d, tuning sample = %d",
			ms_host->mmc->ios.timing, hi_host->tuning_init_sample);
		return 0;
	}
	if (-1 == hi_host->tuning_current_sample) {

		mshci_hi_tuning_clear_flags(hi_host);

		/* set the first sam del as the min_sam_del */
		hi_host->tuning_current_sample =
			hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];
		/* a trick for next "++" */
		hi_host->tuning_current_sample--;
	}

	if (hi_host->tuning_current_sample >=
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM]) {
		/* tuning finish, select the best sam_del */

		/* set sam del to -1, for next tuning */
		hi_host->tuning_current_sample = -1;

		sample_min =
			hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];
		sample_max =
			hi_host->init_tuning_config[3 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM];

#if 0
		begin = -1;
		end = -1;
		for (i = sample_min; i <= sample_max; i++) {
			if (-1 == begin) {
				/* no begin, find begin */
				if (mshci_hi_tuning_get_flags(hi_host, i)) {
					begin = i;
				} else {
					continue;
				}
			} else if (-1 == end) {
				/* no end, find end */
				if (mshci_hi_tuning_get_flags(hi_host, i)) {
					if (i == sample_max) {
						end = sample_max;
					} else {
						continue;
					}
				} else {
					end = i - 1;
				}
			} else {
				/* has begin & end, break */
				break;
			}
		}

		if (-1 == begin) {
			hi_host->tuning_init_sample = (sample_min + sample_max) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
				"tuning err: no good sam_del, timing is %d, tuning_flag = 0x%x",
				ms_host->mmc->ios.timing, hi_host->tuning_sample_flag);
			ret = -1;
		} else if (-1 == end) {
			hi_host->tuning_init_sample = (begin + sample_max) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
					"tuning err: no end! arithmetic error, timing is %d, begin = %d; tuning_flag = 0x%x",
					ms_host->mmc->ios.timing, begin, hi_host->tuning_sample_flag);
			ret = -1;
		} else {
			hi_host->tuning_init_sample = (begin + end) / 2;
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT,
				"tuning OK: timing is %d, tuning sample = %d, tuning_flag = 0x%x",
				ms_host->mmc->ios.timing, hi_host->tuning_init_sample, hi_host->tuning_sample_flag);
			ret = 0;
		}
#else
#define SD_DDR50_TUNNING_WIDTH		8
		/* begin: different delay sel for SD card in DDR50 */
		if ((MMC_TYPE_SD == mmc->card->type) &&
			(MMC_TIMING_UHS_DDR50 == mmc->ios.timing) &&
			(hi_host->init_tuning_config[4 + (ms_host->mmc->ios.timing + 1) * TUNING_INIT_CONFIG_NUM] > 8)) {
			sample_min = sample_min - SD_DDR50_TUNNING_WIDTH;
			hi_host->tuning_sample_flag |= hi_host->tuning_sample_flag >> SD_DDR50_TUNNING_WIDTH;
		}