emmc: save tuning parameter of hs400 [1/1]

PD#SWPL-15199

Problem:
tunig process of hs400 is too slow

Solution:
saved tuning parameter of hs400 on emmc

Verify:
passed on tm2_t962e2_ab311

Change-Id: Ifd1ba375dd93745c9db33a94f3480ebfc21e999f
Signed-off-by: Ruixuan Li <ruixuan.li@amlogic.com>
Signed-off-by: chunlong.cao <chunlong.cao@amlogic.com>
This commit is contained in:
Ruixuan Li
2019-10-12 20:45:18 +08:00
committed by Chris
parent ec7c326bf0
commit 366ccec376
11 changed files with 291 additions and 10 deletions

View File

@@ -1411,6 +1411,7 @@
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
/*caps defined in dts*/
tx_delay = <0>;
save_para = <0>;
max_req_size = <0x20000>; /**128KB*/
gpio_dat3 = <&gpio BOOT_3 GPIO_ACTIVE_HIGH>;
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;

View File

@@ -1410,6 +1410,7 @@
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
/*caps defined in dts*/
tx_delay = <0>;
save_para = <0>;
max_req_size = <0x20000>; /**128KB*/
gpio_dat3 = <&gpio BOOT_3 GPIO_ACTIVE_HIGH>;
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;

View File

@@ -43,6 +43,7 @@
#include <linux/amlogic/aml_sd_emmc_internal.h>
#include <linux/time.h>
#include <linux/random.h>
#include "../../thermal/thermal_core.h"
int aml_fixdiv_calc(unsigned int *fixdiv, struct clock_lay_t *clk)
{
@@ -706,6 +707,9 @@ static int aml_sd_emmc_cali_v3(struct mmc_host *mmc,
cmd.arg = MMC_RANDOM_OFFSET;
else if (!strcmp(pattern, MMC_DTB_NAME))
cmd.arg = MMC_DTB_OFFSET;
else if (!strcmp(pattern, MMC_TUNING_NAME))
cmd.arg = MMC_TUNING_OFFSET;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
stop.opcode = MMC_STOP_TRANSMISSION;
@@ -1132,14 +1136,14 @@ static u32 scan_emmc_cmd_win(struct mmc_host *mmc, int send_status)
for (j = 0; j < repeat_times; j++) {
if (send_status)
err = emmc_send_cmd(mmc,
MMC_SEND_STATUS,
1 << 16,
MMC_RSP_R1 | MMC_CMD_AC);
MMC_SEND_STATUS,
1 << 16,
MMC_RSP_R1 | MMC_CMD_AC);
else
err = single_read_cmd_for_scan(mmc,
MMC_READ_SINGLE_BLOCK,
host->blk_test, 512, 1,
offset);
MMC_READ_SINGLE_BLOCK,
host->blk_test, 512, 1,
offset);
if (!err)
str[i]++;
else
@@ -1302,6 +1306,8 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc)
host->cmd_retune = 1;
host->find_win = 1;
}
gintf3->ds_sht_m = 0;
for (i = 0; i < 64; i++) {
host->is_tunning = 1;
err = emmc_test_bus(mmc);
@@ -1365,7 +1371,6 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc)
static void aml_emmc_hs400_general(struct mmc_host *mmc)
{
update_all_line_eyetest(mmc);
emmc_ds_core_align(mmc);
update_all_line_eyetest(mmc);
@@ -2325,17 +2330,188 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
readl(host->base + SD_EMMC_INTF3));
return err;
}
static long long _para_checksum_calc(struct aml_tuning_para *para)
{
int i = 0;
int size = sizeof(struct aml_tuning_para) - 6 * sizeof(unsigned int);
unsigned int *buffer;
long long checksum = 0;
if (!para)
return 1;
size = size >> 2;
buffer = (unsigned int *)para;
while (i < size)
checksum += buffer[i++];
return checksum;
}
/*
* read tuning para from reserved partition
* and copy it to pdata->para
*/
int aml_read_tuning_para(struct mmc_host *mmc)
{
int off, blk;
int ret;
int para_size;
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
if (pdata->save_para == 0)
return 0;
para_size = sizeof(struct aml_tuning_para);
blk = (para_size - 1) / 512 + 1;
off = MMC_TUNING_OFFSET;
if (blk == 1)
ret = single_read_cmd_for_scan(mmc,
MMC_READ_SINGLE_BLOCK,
host->blk_test, 512,
blk, off);
else
ret = aml_sd_emmc_cali_v3(mmc,
MMC_READ_MULTIPLE_BLOCK,
host->blk_test, 512, blk,
MMC_TUNING_NAME);
if (ret) {
pr_info("read tuning parameter failed\n");
return ret;
}
memcpy(&pdata->para, host->blk_test, para_size);
return ret;
}
/*set para on controller register*/
static void aml_set_tuning_para(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
struct aml_tuning_para *para = &pdata->para;
int temp_index;
u32 delay1, delay2, intf3;
temp_index = para->temperature / 10000;
delay1 = pdata->para.hs4[temp_index].delay1;
delay2 = pdata->para.hs4[temp_index].delay2;
intf3 = pdata->para.hs4[temp_index].intf3;
writel(delay1, host->base + SD_EMMC_DELAY1_V3);
writel(delay2, host->base + SD_EMMC_DELAY2_V3);
writel(intf3, host->base + SD_EMMC_INTF3);
}
/*save parameter on mmc_host pdata*/
static void aml_save_tuning_para(struct mmc_host *mmc)
{
unsigned int checksum;
int temp_index;
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
struct aml_tuning_para *para = &pdata->para;
u32 delay1 = readl(host->base + SD_EMMC_DELAY1_V3);
u32 delay2 = readl(host->base + SD_EMMC_DELAY2_V3);
u32 intf3 = readl(host->base + SD_EMMC_INTF3);
if (pdata->save_para == 0)
return;
temp_index = para->temperature / 10000;
if (para->temperature < 0 || temp_index > 6) {
para->update = 0;
return;
}
pdata->para.hs4[temp_index].delay1 = delay1;
pdata->para.hs4[temp_index].delay2 = delay2;
pdata->para.hs4[temp_index].intf3 = intf3;
pdata->para.hs4[temp_index].flag = 1;
pdata->para.magic = 0x00487e44; /*E~K\0*/
pdata->para.version = 1;
checksum = _para_checksum_calc(para);
pdata->para.checksum = checksum;
}
/*
* check if tuning parameter is exist
* check if temperature is in the 0~69
* check if the parameter has been tuning
* under the current temperature
* check if the data had been broken by checksum
*
* if all four condition above is yes, the tuning parameter
* could be use directly
* otherwise retunning and save parameter
*/
static int aml_para_is_exist(struct mmc_host *mmc)
{
int temperature;
int temp_index;
unsigned int checksum;
struct amlsd_platform *pdata = mmc_priv(mmc);
struct aml_tuning_para *para = &pdata->para;
if (pdata->save_para == 0)
return 0;
temperature = thermal_get_temp_by_index(0);
if (temperature == -1) {
para->update = 0;
pr_info("get temperature failed\n");
return 0;
}
pr_info("current temperature is %d\n", temperature);
temp_index = temperature / 10000;
para->temperature = temperature;
para->update = 1;
/* temperature range is 0 ~ 69 */
if (temperature < 0 || temp_index > 6) {
pr_info("temperature is out of normal range\n");
return 0;
}
if (para->hs4[temp_index].flag == 0) {
pr_info("current temperature %d degree not tuning yet\n",
temperature / 1000);
return 0;
}
checksum = _para_checksum_calc(para);
if (checksum != para->checksum) {
pr_info("warning: checksum is not match\n");
return 0;
}
para->update = 0;
return 1;
}
int aml_post_hs400_timming(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
aml_sd_emmc_clktest(mmc);
if (aml_para_is_exist(mmc)) {
aml_set_tuning_para(mmc);
return 0;
}
if (host->data->chip_type == MMC_CHIP_G12B)
aml_emmc_hs400_Revb(mmc);
else if (host->data->chip_type >= MMC_CHIP_TL1)
aml_emmc_hs400_tl1(mmc);
else
aml_emmc_hs400_general(mmc);
aml_save_tuning_para(mmc);
return 0;
}

View File

@@ -204,11 +204,13 @@ int amlsd_get_platform_data(struct platform_device *pdev,
SD_PARSE_U32_PROP_DEC(child, "card_type",
prop, pdata->card_type);
SD_PARSE_U32_PROP_DEC(child, "tx_delay",
prop, pdata->tx_delay);
prop, pdata->tx_delay);
SD_PARSE_U32_PROP_DEC(child, "save_para",
prop, pdata->save_para);
SD_PARSE_U32_PROP_DEC(child, "latest_dat",
prop, pdata->latest_dat);
prop, pdata->latest_dat);
SD_PARSE_U32_PROP_DEC(child, "co_phase",
prop, pdata->co_phase);
prop, pdata->co_phase);
if (aml_card_type_mmc(pdata)) {
/*tx_phase set default value first*/
SD_PARSE_U32_PROP_DEC(child, "tx_phase",

View File

@@ -778,6 +778,41 @@ static int mmc_transfer(struct mmc_card *card, unsigned int dev_addr,
return ret;
}
/*write tuning para on emmc, the offset is 0x14400*/
static int amlmmc_write_tuning_para(struct mmc_card *card,
unsigned int dev_addr)
{
unsigned int size;
struct amlsd_platform *pdata = mmc_priv(card->host);
struct aml_tuning_para *parameter = &pdata->para;
unsigned int *buf;
int para_size;
int blocks;
if (pdata->save_para == 0)
return 0;
if (parameter->update == 0)
return 0;
parameter->update = 0;
para_size = sizeof(struct aml_tuning_para);
blocks = (para_size - 1) / 512 + 1;
size = blocks << card->csd.read_blkbits;
buf = kmalloc(size, GFP_KERNEL);
memset(buf, 0, size);
memcpy(buf, parameter, sizeof(struct aml_tuning_para));
mmc_claim_host(card->host);
mmc_transfer(card, dev_addr, blocks, buf, 1);
mmc_release_host(card->host);
kfree(buf);
return 0;
}
int mmc_read_internal(struct mmc_card *card, unsigned int dev_addr,
unsigned int blocks, void *buf)
{

View File

@@ -1164,6 +1164,9 @@ static int mmc_select_hs400(struct mmc_card *card)
err = mmc_switch_status(card);
if (err)
goto out_err;
#ifdef CONFIG_AMLOGIC_MMC
aml_read_tuning_para(host);
#endif
/* Switch card to DDR */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,

View File

@@ -720,6 +720,31 @@ static void thermal_zone_device_check(struct work_struct *work)
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
int thermal_get_temp_by_index(int id)
{
struct thermal_zone_device *pos = NULL;
int temperature, ret = 0;
list_for_each_entry(pos, &thermal_tz_list, node) {
if (pos->id == id) {
ret = 1;
break;
}
}
if (ret) {
ret = thermal_zone_get_temp(pos, &temperature);
if (ret)
return -1;
return temperature;
}
return -1;
}
#endif
/* sys I/F for thermal zone */
#define to_thermal_zone(_dev) \

View File

@@ -57,6 +57,9 @@ struct thermal_instance {
int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);
#ifdef CONFIG_AMLOGIC_TEMP_SENSOR
int thermal_get_temp_by_index(int id);
#endif
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
int thermal_gov_step_wise_register(void);
void thermal_gov_step_wise_unregister(void);

View File

@@ -257,10 +257,40 @@ struct clock_lay_t {
#define TODLY_MIN_NS (2)
#define TODLY_MAX_NS (14)
struct hs400_para {
unsigned int delay1;
unsigned int delay2;
unsigned int intf3;
unsigned int flag;
};
struct hs200_para {
unsigned int adjust;
};
struct hs_para {
unsigned int adjust;
};
struct aml_tuning_para {
unsigned int chip_id[4];
unsigned int magic;
unsigned int vddee;
struct hs400_para hs4[7];
struct hs200_para hs2;
struct hs_para hs;
unsigned int version;
unsigned int busmod;
unsigned int update;
int temperature;
long long checksum;
};
struct amlsd_platform {
struct amlsd_host *host;
struct mmc_host *mmc;
struct list_head sibling;
struct aml_tuning_para para;
u32 ocr_avail;
u32 port;
#define PORT_SDIO_A 0
@@ -281,6 +311,7 @@ struct amlsd_platform {
unsigned int card_capacity;
unsigned int tx_phase;
unsigned int tx_delay;
unsigned int save_para;
unsigned int co_phase;
unsigned int f_min;
unsigned int f_max;

View File

@@ -23,6 +23,7 @@
/* MMC Partition Table */
#define MMC_PARTITIONS_MAGIC "MPT"
#define MMC_RESERVED_NAME "reserved"
#define MMC_TUNING_NAME "tuning"
#define SZ_1M 0x00100000
@@ -36,6 +37,7 @@
#define MMC_DTB_OFFSET ((SZ_1M*(36+4))/512)
/* the size of bootloader partition */
#define MMC_BOOT_PARTITION_SIZE (4*SZ_1M)
#define MMC_TUNING_OFFSET 0X14400
/* the size of reserve space behind bootloader partition */
#define MMC_BOOT_PARTITION_RESERVED (32*SZ_1M)

View File

@@ -584,4 +584,6 @@ static inline void mmc_retune_recheck(struct mmc_host *host)
void mmc_retune_pause(struct mmc_host *host);
void mmc_retune_unpause(struct mmc_host *host);
int aml_read_tuning_para(struct mmc_host *mmc);
#endif /* LINUX_MMC_HOST_H */