mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
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:
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user