Message ID | 20170612074602.55280-1-liwei213@huawei.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, On 06/12/2017 11:27 PM, Jaehoon Chung wrote: > Hi Li, > > On 2017년 06월 12일 16:46, liwei wrote: >> Add sd card support for hi3660 soc >> >> Major changes in v3: >> - solve review comments from Heiner Kallweit. >> *use the GENMASK and FIELD_PREP macros replace the bit shift operation. >> *use usleep_range() replace udelay() and mdelay(). > > I had added the some comments about your previous patch. > Refer to below... > > https://patchwork.kernel.org/patch/9747495/ Before sending patch, run checkpatch...I will not apply this patch. Best Regards, Jaehoon Chung > >> >> Signed-off-by: Li Wei <liwei213@huawei.com> >> Signed-off-by: Chen Jun <chenjun14@huawei.com> >> --- > > Locate changelog at here. > > Best Regards, > Jaehoon Chung > >> drivers/mmc/host/dw_mmc-k3.c | 314 +++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 314 insertions(+) >> >> diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c >> index e38fb0020bb1..a6e13bd83b9f 100644 >> --- a/drivers/mmc/host/dw_mmc-k3.c >> +++ b/drivers/mmc/host/dw_mmc-k3.c >> @@ -8,6 +8,8 @@ >> * (at your option) any later version. >> */ >> >> +#include <linux/bitops.h> >> +#include <linux/bitfield.h> >> #include <linux/clk.h> >> #include <linux/mfd/syscon.h> >> #include <linux/mmc/host.h> >> @@ -28,7 +30,40 @@ >> #define AO_SCTRL_SEL18 BIT(10) >> #define AO_SCTRL_CTRL3 0x40C >> >> +#define DWMMC_SD_ID 1 >> +#define DWMMC_SDIO_ID 2 >> + >> +#define SOC_SCTRL_SCPERCTRL5 (0x314) >> +#define SDCARD_IO_SEL18 BIT(2) >> + >> +#define GENCLK_DIV (7) >> + >> +#define GPIO_CLK_ENABLE BIT(16) >> +#define GPIO_CLK_DIV_MASK GENMASK(11, 8) >> +#define GPIO_USE_SAMPLE_DLY_MASK GENMASK(13, 13) >> +#define UHS_REG_EXT_SAMPLE_PHASE_MASK GENMASK(20, 16) >> +#define UHS_REG_EXT_SAMPLE_DRVPHASE_MASK GENMASK(25, 21) >> +#define UHS_REG_EXT_SAMPLE_DLY_MASK GENMASK(30, 26) >> + >> +#define SDMMC_UHS_REG_EXT 0x108 >> +#define SDMMC_ENABLE_SHIFT 0x110 >> + >> +#define TIMING_MODE 3 >> +#define TIMING_CFG_NUM 10 >> + >> +#define PULL_DOWN BIT(1) >> +#define PULL_UP BIT(0) >> + >> +#define NUM_PHASES (40) >> + >> +#define ENABLE_SHIFT_MIN_SMPL (4) >> +#define ENABLE_SHIFT_MAX_SMPL (12) >> +#define USE_DLY_MIN_SMPL (11) >> +#define USE_DLY_MAX_SMPL (14) >> + >> struct k3_priv { >> + u8 ctrl_id; >> + u32 cur_speed; >> struct regmap *reg; >> }; >> >> @@ -38,6 +73,41 @@ static unsigned long dw_mci_hi6220_caps[] = { >> 0 >> }; >> >> +struct hs_timing { >> + int drv_phase; >> + int sam_dly; >> + int sam_phase_max; >> + int sam_phase_min; >> +}; >> + >> +struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = { >> + { /* reserved */ }, >> + { /* SD */ >> + {7, 0, 15, 15,}, /* 0: LEGACY 400k */ >> + {6, 0, 4, 4,}, /* 1: MMC_HS */ >> + {6, 0, 3, 3,}, /* 2: SD_HS */ >> + {6, 0, 15, 15,}, /* 3: SDR12 */ >> + {6, 0, 2, 2,}, /* 4: SDR25 */ >> + {4, 0, 11, 0,}, /* 5: SDR50 */ >> + {6, 4, 15, 0,}, /* 6: SDR104 */ >> + {0}, /* 7: DDR50 */ >> + {0}, /* 8: DDR52 */ >> + {0}, /* 9: HS200 */ >> + }, >> + { /* SDIO */ >> + {7, 0, 15, 15,}, /* 0: LEGACY 400k */ >> + {0}, /* 1: MMC_HS */ >> + {6, 0, 15, 15,}, /* 2: SD_HS */ >> + {6, 0, 15, 15,}, /* 3: SDR12 */ >> + {6, 0, 0, 0,}, /* 4: SDR25 */ >> + {4, 0, 12, 0,}, /* 5: SDR50 */ >> + {5, 4, 15, 0,}, /* 6: SDR104 */ >> + {0}, /* 7: DDR50 */ >> + {0}, /* 8: DDR52 */ >> + {0}, /* 9: HS200 */ >> + } >> +}; >> + >> static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) >> { >> int ret; >> @@ -66,6 +136,10 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host) >> if (IS_ERR(priv->reg)) >> priv->reg = NULL; >> >> + priv->ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); >> + if (priv->ctrl_id < 0) >> + priv->ctrl_id = 0; >> + >> host->priv = priv; >> return 0; >> } >> @@ -144,7 +218,242 @@ static const struct dw_mci_drv_data hi6220_data = { >> .execute_tuning = dw_mci_hi6220_execute_tuning, >> }; >> >> +static void dw_mci_hs_set_timing(struct dw_mci *host, int timing, int sam_phase) >> +{ >> + int drv_phase; >> + int sam_dly; >> + int ctrl_id; >> + int use_sam_dly = 0; >> + int enable_shift = 0; >> + int reg_value; >> + struct k3_priv *priv; >> + >> + priv = host->priv; >> + ctrl_id = priv->ctrl_id; >> + >> + drv_phase = hs_timing_cfg[ctrl_id][timing].drv_phase; >> + sam_dly = hs_timing_cfg[ctrl_id][timing].sam_dly; >> + if (sam_phase == -1) >> + sam_phase = (hs_timing_cfg[ctrl_id][timing].sam_phase_max + >> + hs_timing_cfg[ctrl_id][timing].sam_phase_min) / 2; >> + >> + if (timing == MMC_TIMING_UHS_SDR50 || >> + timing == MMC_TIMING_UHS_SDR104) { >> + if (sam_phase >= ENABLE_SHIFT_MIN_SMPL && >> + sam_phase <= ENABLE_SHIFT_MAX_SMPL) >> + enable_shift = 1; >> + } >> + if (timing == MMC_TIMING_UHS_SDR104) { >> + if (sam_phase >= USE_DLY_MIN_SMPL && >> + sam_phase <= USE_DLY_MAX_SMPL) >> + use_sam_dly = 1; >> + } >> + >> + mci_writel(host, GPIO, 0x0); >> + usleep_range(5, 10); >> + >> + reg_value = FIELD_PREP(UHS_REG_EXT_SAMPLE_PHASE_MASK, sam_phase) |\ >> + FIELD_PREP(UHS_REG_EXT_SAMPLE_DLY_MASK ,sam_dly) |\ >> + FIELD_PREP(UHS_REG_EXT_SAMPLE_DRVPHASE_MASK,drv_phase); >> + mci_writel(host, UHS_REG_EXT, reg_value); >> + >> + mci_writel(host, ENABLE_SHIFT, enable_shift); >> + >> + reg_value = FIELD_PREP(GPIO_CLK_DIV_MASK, GENCLK_DIV) |\ >> + FIELD_PREP(GPIO_USE_SAMPLE_DLY_MASK,use_sam_dly); >> + mci_writel(host, GPIO, (unsigned int)reg_value | GPIO_CLK_ENABLE); >> + >> + /* We should delay 1ms wait for timing setting finished. */ >> + usleep_range(1000, 2000); >> +} >> + >> +int dw_mci_hi3660_init(struct dw_mci *host) >> +{ >> + /* set threshold to 512 bytes */ >> + mci_writel(host, CDTHRCTL, 0x02000001); >> + >> + dw_mci_hs_set_timing(host, MMC_TIMING_LEGACY, -1); >> + host->bus_hz /= (GENCLK_DIV + 1); >> + >> + return 0; >> +} >> + >> +static int dw_mci_set_sel18(struct dw_mci *host, bool set) >> +{ >> + int ret; >> + unsigned int val; >> + struct k3_priv *priv; >> + >> + priv = host->priv; >> + >> + val = set ? SDCARD_IO_SEL18 : 0; >> + ret = regmap_update_bits(priv->reg, SOC_SCTRL_SCPERCTRL5, >> + SDCARD_IO_SEL18, val); >> + if (ret) { >> + dev_err(host->dev, "sel18 %u error\n", val); >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +void dw_mci_hi3660_set_ios(struct dw_mci *host, struct mmc_ios *ios) >> +{ >> + int ret; >> + unsigned long wanted; >> + unsigned long actual; >> + struct k3_priv *priv = host->priv; >> + >> + if (!ios->clock || ios->clock == priv->cur_speed) >> + return; >> + >> + wanted = ios->clock * (GENCLK_DIV + 1); >> + ret = clk_set_rate(host->ciu_clk, wanted); >> + if (ret) { >> + dev_err(host->dev, "failed to set rate %luHz\n", wanted); >> + return; >> + } >> + actual = clk_get_rate(host->ciu_clk); >> + >> + dw_mci_hs_set_timing(host, ios->timing, -1); >> + host->bus_hz = actual / (GENCLK_DIV + 1); >> + host->current_speed = 0; >> + priv->cur_speed = host->bus_hz; >> +} >> + >> +static int dw_mci_get_best_clksmpl(unsigned int sample_flag) >> +{ >> + int i; >> + int interval; >> + unsigned int v; >> + unsigned int len; >> + unsigned int range_start = 0; >> + unsigned int range_length = 0; >> + unsigned int middle_range = 0; >> + >> + if (!sample_flag) >> + return -EIO; >> + >> + if (~sample_flag == 0) >> + return 0; >> + >> + i = ffs(sample_flag) - 1; >> + >> + /*A clock cycle is divided into 32 phases, >> + *each of which is represented by a bit, finding the optimal phase. >> + */ >> + while (i < 32) { >> + v = ror32(sample_flag, i); >> + len = ffs(~v) - 1; >> + >> + if (len > range_length) { >> + range_length = len; >> + range_start = i; >> + } >> + >> + interval = ffs(v >> len) - 1; >> + if (interval < 0) >> + break; >> + >> + i += len + interval; >> + } >> + >> + middle_range = range_start + range_length / 2; >> + if (middle_range >= 32) >> + middle_range %= 32; >> + >> + return middle_range; >> +} >> + >> +static int dw_mci_hi3660_execute_tuning(struct dw_mci_slot *slot, u32 opcode) >> +{ >> + int i = 0; >> + struct dw_mci *host = slot->host; >> + struct mmc_host *mmc = slot->mmc; >> + int sam_phase = 0; >> + u32 tuning_sample_flag = 0; >> + int best_clksmpl = 0; >> + >> + for (i = 0; i < NUM_PHASES; ++i, ++sam_phase) { >> + sam_phase %= 32; >> + >> + mci_writel(host, TMOUT, ~0); >> + dw_mci_hs_set_timing(host, mmc->ios.timing, sam_phase); >> + >> + if (!mmc_send_tuning(mmc, opcode, NULL)) >> + tuning_sample_flag |= (1 << sam_phase); >> + else >> + tuning_sample_flag &= ~(1 << sam_phase); >> + } >> + >> + best_clksmpl = dw_mci_get_best_clksmpl(tuning_sample_flag); >> + if (best_clksmpl < 0) { >> + dev_err(host->dev, "All phases bad!\n"); >> + return -EIO; >> + } >> + >> + dw_mci_hs_set_timing(host, mmc->ios.timing, best_clksmpl); >> + >> + dev_info(host->dev, "tuning ok best_clksmpl %u tuning_sample_flag %x\n", >> + best_clksmpl, tuning_sample_flag); >> + return 0; >> +} >> + >> +static int dw_mci_hi3660_switch_voltage(struct mmc_host *mmc, >> + struct mmc_ios *ios) >> +{ >> + int ret; >> + int min_uv = 0; >> + int max_uv = 0; >> + struct dw_mci_slot *slot = mmc_priv(mmc); >> + struct k3_priv *priv; >> + struct dw_mci *host; >> + >> + host = slot->host; >> + priv = host->priv; >> + >> + if (!priv || !priv->reg) >> + return 0; >> + >> + if (priv->ctrl_id == DWMMC_SDIO_ID) >> + return 0; >> + >> + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { >> + ret = dw_mci_set_sel18(host, 0); >> + if (ret) >> + return ret; >> + min_uv = 2950000; >> + max_uv = 2950000; >> + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { >> + ret = dw_mci_set_sel18(host, 1); >> + if (ret) >> + return ret; >> + min_uv = 1800000; >> + max_uv = 1800000; >> + } >> + >> + if (IS_ERR_OR_NULL(mmc->supply.vqmmc)) >> + return 0; >> + >> + ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); >> + if (ret) { >> + dev_dbg(host->dev, "Regulator set error %d: %d - %d\n", >> + ret, min_uv, max_uv); >> + return ret; >> + } >> + return 0; >> +} >> + >> +static const struct dw_mci_drv_data hi3660_data = { >> + .init = dw_mci_hi3660_init, >> + .set_ios = dw_mci_hi3660_set_ios, >> + .parse_dt = dw_mci_hi6220_parse_dt, >> + .execute_tuning = dw_mci_hi3660_execute_tuning, >> + .switch_voltage = dw_mci_hi3660_switch_voltage, >> +}; >> + >> static const struct of_device_id dw_mci_k3_match[] = { >> + { .compatible = "hisilicon,hi3660-dw-mshc", .data = &hi3660_data, }, >> { .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, }, >> { .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, }, >> {}, >> @@ -155,6 +464,11 @@ static int dw_mci_k3_probe(struct platform_device *pdev) >> { >> const struct dw_mci_drv_data *drv_data; >> const struct of_device_id *match; >> + struct reset_control *rst; >> + >> + rst = devm_reset_control_get(&pdev->dev, NULL); >> + if (!IS_ERR(rst)) >> + reset_control_reset(rst); >> >> match = of_match_node(dw_mci_k3_match, pdev->dev.of_node); >> drv_data = match->data; >> > > > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
SGksIEphZWhvb24NClRoYW5rIHlvdSB2ZXJ5IG11Y2ggZm9yIHlvdXIgYWR2aWNlczsgSSdsbCBm b2xsb3cgeW91ciBhZHZpY2VzIGFuZCBmaXggYWxsIHRoZSBvdGhlciBwbGFjZXMgYnV0IGV4Y2Vw dCBmb3IgdGhlIGZvbGxvd2luZyBvbmU6DQoNCiJZb3UgaGF2ZSBhc3N1bXB0aW9uLi4uYWx3YXlz Lg0KbXNoYzAgLT4gZU1NQywgDQptc2hjMSAtPiBTRA0KbXNoYzIgLT4gU0RJTyINCg0KeWVzLCBt c2hjMCAtPiBlTU1DLCBtc2hjMSAtPiBTRCxtc2hjMiAtPiBTRElPLiBDYW4geW91IHBvaW50IGl0 IG91dCBpbiBkZXRhaWw/IA0KDQpUaGFua3MhDQoNCg0KLS0tLS3pgq7ku7bljp/ku7YtLS0tLQ0K 5Y+R5Lu25Lq6OiBKYWVob29uIENodW5nIFttYWlsdG86amg4MC5jaHVuZ0BnbWFpbC5jb21dIA0K 5Y+R6YCB5pe26Ze0OiAyMDE35bm0NuaciDEy5pelIDIyOjI4DQrmlLbku7bkuro6IGxpd2VpIChD TSk7IHVsZi5oYW5zc29uQGxpbmFyby5vcmc7IGFkcmlhbi5odW50ZXJAaW50ZWwuY29tOyBqaDgw LmNodW5nQHNhbXN1bmcuY29tOyBzaGF3bi5saW5Acm9jay1jaGlwcy5jb207IHdzYStyZW5lc2Fz QHNhbmctZW5naW5lZXJpbmcuY29tOyBoa2FsbHdlaXQxQGdtYWlsLmNvbTsgbGludXgtbW1jQHZn ZXIua2VybmVsLm9yZzsgbGludXgta2VybmVsQHZnZXIua2VybmVsLm9yZw0K5oqE6YCBOiBndW9k b25nLnh1QGxpbmFyby5vcmcNCuS4u+mimDogUmU6IFtQQVRDSCB2M10gbW1jOiBkd19tbWMtazM6 IGFkZCBzZCBzdXBwb3J0IGZvciBoaTM2NjANCg0KSGkgTGksDQoNCk9uIDIwMTfrhYQgMDbsm5Qg MTLsnbwgMTY6NDYsIGxpd2VpIHdyb3RlOg0KPiBBZGQgc2QgY2FyZCBzdXBwb3J0IGZvciBoaTM2 NjAgc29jDQo+IA0KPiBNYWpvciBjaGFuZ2VzIGluIHYzOg0KPiAgLSBzb2x2ZSByZXZpZXcgY29t bWVudHMgZnJvbSBIZWluZXIgS2FsbHdlaXQuDQo+ICAgICp1c2UgdGhlIEdFTk1BU0sgYW5kIEZJ RUxEX1BSRVAgbWFjcm9zIHJlcGxhY2UgdGhlIGJpdCBzaGlmdCBvcGVyYXRpb24uDQo+ICAgICp1 c2UgdXNsZWVwX3JhbmdlKCkgcmVwbGFjZSB1ZGVsYXkoKSBhbmQgbWRlbGF5KCkuDQoNCkkgaGFk IGFkZGVkIHRoZSBzb21lIGNvbW1lbnRzIGFib3V0IHlvdXIgcHJldmlvdXMgcGF0Y2guDQpSZWZl ciB0byBiZWxvdy4uLg0KDQpodHRwczovL3BhdGNod29yay5rZXJuZWwub3JnL3BhdGNoLzk3NDc0 OTUvDQoNCj4gDQo+IFNpZ25lZC1vZmYtYnk6IExpIFdlaSA8bGl3ZWkyMTNAaHVhd2VpLmNvbT4N Cj4gU2lnbmVkLW9mZi1ieTogQ2hlbiBKdW4gPGNoZW5qdW4xNEBodWF3ZWkuY29tPg0KPiAtLS0N Cg0KTG9jYXRlIGNoYW5nZWxvZyBhdCBoZXJlLg0KDQpCZXN0IFJlZ2FyZHMsDQpKYWVob29uIENo dW5nDQoNCj4gIGRyaXZlcnMvbW1jL2hvc3QvZHdfbW1jLWszLmMgfCAzMTQgDQo+ICsrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gIDEgZmlsZSBjaGFuZ2VkLCAz MTQgaW5zZXJ0aW9ucygrKQ0KPiANCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbW1jL2hvc3QvZHdf bW1jLWszLmMgDQo+IGIvZHJpdmVycy9tbWMvaG9zdC9kd19tbWMtazMuYyBpbmRleCBlMzhmYjAw MjBiYjEuLmE2ZTEzYmQ4M2I5ZiAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9tbWMvaG9zdC9kd19t bWMtazMuYw0KPiArKysgYi9kcml2ZXJzL21tYy9ob3N0L2R3X21tYy1rMy5jDQo+IEBAIC04LDYg KzgsOCBAQA0KPiAgICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gICAq Lw0KPiAgDQo+ICsjaW5jbHVkZSA8bGludXgvYml0b3BzLmg+DQo+ICsjaW5jbHVkZSA8bGludXgv Yml0ZmllbGQuaD4NCj4gICNpbmNsdWRlIDxsaW51eC9jbGsuaD4NCj4gICNpbmNsdWRlIDxsaW51 eC9tZmQvc3lzY29uLmg+DQo+ICAjaW5jbHVkZSA8bGludXgvbW1jL2hvc3QuaD4NCj4gQEAgLTI4 LDcgKzMwLDQwIEBADQo+ICAjZGVmaW5lIEFPX1NDVFJMX1NFTDE4CQlCSVQoMTApDQo+ICAjZGVm aW5lIEFPX1NDVFJMX0NUUkwzCQkweDQwQw0KPiAgDQo+ICsjZGVmaW5lIERXTU1DX1NEX0lEICAg MQ0KPiArI2RlZmluZSBEV01NQ19TRElPX0lEIDINCj4gKw0KPiArI2RlZmluZSBTT0NfU0NUUkxf U0NQRVJDVFJMNSAgICAoMHgzMTQpDQo+ICsjZGVmaW5lIFNEQ0FSRF9JT19TRUwxOCAgICAgICAg IEJJVCgyKQ0KPiArDQo+ICsjZGVmaW5lIEdFTkNMS19ESVYgKDcpDQo+ICsNCj4gKyNkZWZpbmUg R1BJT19DTEtfRU5BQkxFICAgICAgICAgICAgICAgICAgIEJJVCgxNikNCj4gKyNkZWZpbmUgR1BJ T19DTEtfRElWX01BU0sgICAgICAgICAgICAgICAgIEdFTk1BU0soMTEsIDgpDQo+ICsjZGVmaW5l IEdQSU9fVVNFX1NBTVBMRV9ETFlfTUFTSyAgICAgICAgICBHRU5NQVNLKDEzLCAxMykNCj4gKyNk ZWZpbmUgVUhTX1JFR19FWFRfU0FNUExFX1BIQVNFX01BU0sgICAgIEdFTk1BU0soMjAsIDE2KQ0K PiArI2RlZmluZSBVSFNfUkVHX0VYVF9TQU1QTEVfRFJWUEhBU0VfTUFTSyAgR0VOTUFTSygyNSwg MjEpDQo+ICsjZGVmaW5lIFVIU19SRUdfRVhUX1NBTVBMRV9ETFlfTUFTSyAgICAgICBHRU5NQVNL KDMwLCAyNikNCj4gKw0KPiArI2RlZmluZSBTRE1NQ19VSFNfUkVHX0VYVAkweDEwOA0KPiArI2Rl ZmluZSBTRE1NQ19FTkFCTEVfU0hJRlQJMHgxMTANCj4gKw0KPiArI2RlZmluZSBUSU1JTkdfTU9E RSAgICAgMw0KPiArI2RlZmluZSBUSU1JTkdfQ0ZHX05VTSAxMA0KPiArDQo+ICsjZGVmaW5lIFBV TExfRE9XTiBCSVQoMSkNCj4gKyNkZWZpbmUgUFVMTF9VUCAgIEJJVCgwKQ0KPiArDQo+ICsjZGVm aW5lIE5VTV9QSEFTRVMgKDQwKQ0KPiArDQo+ICsjZGVmaW5lIEVOQUJMRV9TSElGVF9NSU5fU01Q TCAoNCkNCj4gKyNkZWZpbmUgRU5BQkxFX1NISUZUX01BWF9TTVBMICgxMikNCj4gKyNkZWZpbmUg VVNFX0RMWV9NSU5fU01QTCAoMTEpDQo+ICsjZGVmaW5lIFVTRV9ETFlfTUFYX1NNUEwgKDE0KQ0K PiArDQo+ICBzdHJ1Y3QgazNfcHJpdiB7DQo+ICsJdTggY3RybF9pZDsNCj4gKwl1MzIgY3VyX3Nw ZWVkOw0KPiAgCXN0cnVjdCByZWdtYXAJKnJlZzsNCj4gIH07DQo+ICANCj4gQEAgLTM4LDYgKzcz LDQxIEBAIHN0YXRpYyB1bnNpZ25lZCBsb25nIGR3X21jaV9oaTYyMjBfY2Fwc1tdID0gew0KPiAg CTANCj4gIH07DQo+ICANCj4gK3N0cnVjdCBoc190aW1pbmcgew0KPiArCWludCBkcnZfcGhhc2U7 DQo+ICsJaW50IHNhbV9kbHk7DQo+ICsJaW50IHNhbV9waGFzZV9tYXg7DQo+ICsJaW50IHNhbV9w aGFzZV9taW47DQo+ICt9Ow0KPiArDQo+ICtzdHJ1Y3QgaHNfdGltaW5nIGhzX3RpbWluZ19jZmdb VElNSU5HX01PREVdW1RJTUlOR19DRkdfTlVNXSA9IHsNCj4gKwl7IC8qIHJlc2VydmVkICovIH0s DQo+ICsJeyAvKiBTRCAqLw0KPiArCQl7NywgMCwgMTUsIDE1LH0sICAvKiAwOiBMRUdBQ1kgNDAw ayAqLw0KPiArCQl7NiwgMCwgIDQsICA0LH0sICAvKiAxOiBNTUNfSFMgKi8NCj4gKwkJezYsIDAs ICAzLCAgMyx9LCAgLyogMjogU0RfSFMgKi8NCj4gKwkJezYsIDAsIDE1LCAxNSx9LCAgLyogMzog U0RSMTIgKi8NCj4gKwkJezYsIDAsICAyLCAgMix9LCAgLyogNDogU0RSMjUgKi8NCj4gKwkJezQs IDAsIDExLCAgMCx9LCAgLyogNTogU0RSNTAgKi8NCj4gKwkJezYsIDQsIDE1LCAgMCx9LCAgLyog NjogU0RSMTA0ICovDQo+ICsJCXswfSwgICAgICAgICAgICAgIC8qIDc6IEREUjUwICovDQo+ICsJ CXswfSwgICAgICAgICAgICAgIC8qIDg6IEREUjUyICovDQo+ICsJCXswfSwgICAgICAgICAgICAg IC8qIDk6IEhTMjAwICovDQo+ICsJfSwNCj4gKwl7IC8qIFNESU8gKi8NCj4gKwkJezcsIDAsIDE1 LCAxNSx9LCAgLyogMDogTEVHQUNZIDQwMGsgKi8NCj4gKwkJezB9LCAgICAgICAgICAgICAgLyog MTogTU1DX0hTICovDQo+ICsJCXs2LCAwLCAxNSwgMTUsfSwgIC8qIDI6IFNEX0hTICovDQo+ICsJ CXs2LCAwLCAxNSwgMTUsfSwgIC8qIDM6IFNEUjEyICovDQo+ICsJCXs2LCAwLCAgMCwgIDAsfSwg IC8qIDQ6IFNEUjI1ICovDQo+ICsJCXs0LCAwLCAxMiwgIDAsfSwgIC8qIDU6IFNEUjUwICovDQo+ ICsJCXs1LCA0LCAxNSwgIDAsfSwgIC8qIDY6IFNEUjEwNCAqLw0KPiArCQl7MH0sICAgICAgICAg ICAgICAvKiA3OiBERFI1MCAqLw0KPiArCQl7MH0sICAgICAgICAgICAgICAvKiA4OiBERFI1MiAq Lw0KPiArCQl7MH0sICAgICAgICAgICAgICAvKiA5OiBIUzIwMCAqLw0KPiArCX0NCj4gK307DQo+ ICsNCj4gIHN0YXRpYyB2b2lkIGR3X21jaV9rM19zZXRfaW9zKHN0cnVjdCBkd19tY2kgKmhvc3Qs IHN0cnVjdCBtbWNfaW9zIA0KPiAqaW9zKSAgew0KPiAgCWludCByZXQ7DQo+IEBAIC02Niw2ICsx MzYsMTAgQEAgc3RhdGljIGludCBkd19tY2lfaGk2MjIwX3BhcnNlX2R0KHN0cnVjdCBkd19tY2kg Kmhvc3QpDQo+ICAJaWYgKElTX0VSUihwcml2LT5yZWcpKQ0KPiAgCQlwcml2LT5yZWcgPSBOVUxM Ow0KPiAgDQo+ICsJcHJpdi0+Y3RybF9pZCA9IG9mX2FsaWFzX2dldF9pZChob3N0LT5kZXYtPm9m X25vZGUsICJtc2hjIik7DQo+ICsJaWYgKHByaXYtPmN0cmxfaWQgPCAwKQ0KPiArCQlwcml2LT5j dHJsX2lkID0gMDsNCj4gKw0KPiAgCWhvc3QtPnByaXYgPSBwcml2Ow0KPiAgCXJldHVybiAwOw0K PiAgfQ0KPiBAQCAtMTQ0LDcgKzIxOCwyNDIgQEAgc3RhdGljIGNvbnN0IHN0cnVjdCBkd19tY2lf ZHJ2X2RhdGEgaGk2MjIwX2RhdGEgPSB7DQo+ICAJLmV4ZWN1dGVfdHVuaW5nCQk9IGR3X21jaV9o aTYyMjBfZXhlY3V0ZV90dW5pbmcsDQo+ICB9Ow0KPiAgDQo+ICtzdGF0aWMgdm9pZCBkd19tY2lf aHNfc2V0X3RpbWluZyhzdHJ1Y3QgZHdfbWNpICpob3N0LCBpbnQgdGltaW5nLCBpbnQgDQo+ICtz YW1fcGhhc2UpIHsNCj4gKwlpbnQgZHJ2X3BoYXNlOw0KPiArCWludCBzYW1fZGx5Ow0KPiArCWlu dCBjdHJsX2lkOw0KPiArCWludCB1c2Vfc2FtX2RseSA9IDA7DQo+ICsJaW50IGVuYWJsZV9zaGlm dCA9IDA7DQo+ICsJaW50IHJlZ192YWx1ZTsNCj4gKwlzdHJ1Y3QgazNfcHJpdiAqcHJpdjsNCj4g Kw0KPiArCXByaXYgPSBob3N0LT5wcml2Ow0KPiArCWN0cmxfaWQgPSBwcml2LT5jdHJsX2lkOw0K PiArDQo+ICsJZHJ2X3BoYXNlID0gaHNfdGltaW5nX2NmZ1tjdHJsX2lkXVt0aW1pbmddLmRydl9w aGFzZTsNCj4gKwlzYW1fZGx5ICAgPSBoc190aW1pbmdfY2ZnW2N0cmxfaWRdW3RpbWluZ10uc2Ft X2RseTsNCj4gKwlpZiAoc2FtX3BoYXNlID09IC0xKQ0KPiArCQlzYW1fcGhhc2UgPSAoaHNfdGlt aW5nX2NmZ1tjdHJsX2lkXVt0aW1pbmddLnNhbV9waGFzZV9tYXggKw0KPiArCQkJICAgICBoc190 aW1pbmdfY2ZnW2N0cmxfaWRdW3RpbWluZ10uc2FtX3BoYXNlX21pbikgLyAyOw0KPiArDQo+ICsJ aWYgKHRpbWluZyA9PSBNTUNfVElNSU5HX1VIU19TRFI1MCB8fA0KPiArCSAgICB0aW1pbmcgPT0g TU1DX1RJTUlOR19VSFNfU0RSMTA0KSB7DQo+ICsJCWlmIChzYW1fcGhhc2UgPj0gRU5BQkxFX1NI SUZUX01JTl9TTVBMICYmDQo+ICsJCSAgICBzYW1fcGhhc2UgPD0gRU5BQkxFX1NISUZUX01BWF9T TVBMKQ0KPiArCQkJZW5hYmxlX3NoaWZ0ID0gMTsNCj4gKwl9DQo+ICsJaWYgKHRpbWluZyA9PSBN TUNfVElNSU5HX1VIU19TRFIxMDQpIHsNCj4gKwkJaWYgKHNhbV9waGFzZSA+PSBVU0VfRExZX01J Tl9TTVBMICYmDQo+ICsJCSAgICBzYW1fcGhhc2UgPD0gVVNFX0RMWV9NQVhfU01QTCkNCj4gKwkJ CXVzZV9zYW1fZGx5ID0gMTsNCj4gKwl9DQo+ICsNCj4gKwltY2lfd3JpdGVsKGhvc3QsIEdQSU8s IDB4MCk7DQo+ICsJdXNsZWVwX3JhbmdlKDUsIDEwKTsNCj4gKw0KPiArCXJlZ192YWx1ZSA9IEZJ RUxEX1BSRVAoVUhTX1JFR19FWFRfU0FNUExFX1BIQVNFX01BU0ssIHNhbV9waGFzZSkgfFwNCj4g KwkJCQlGSUVMRF9QUkVQKFVIU19SRUdfRVhUX1NBTVBMRV9ETFlfTUFTSyAsc2FtX2RseSkgfFwN Cj4gKwkJCQlGSUVMRF9QUkVQKFVIU19SRUdfRVhUX1NBTVBMRV9EUlZQSEFTRV9NQVNLLGRydl9w aGFzZSk7CQkNCj4gKwltY2lfd3JpdGVsKGhvc3QsIFVIU19SRUdfRVhULCByZWdfdmFsdWUpOw0K PiArDQo+ICsJbWNpX3dyaXRlbChob3N0LCBFTkFCTEVfU0hJRlQsIGVuYWJsZV9zaGlmdCk7DQo+ ICsNCj4gKwlyZWdfdmFsdWUgPSBGSUVMRF9QUkVQKEdQSU9fQ0xLX0RJVl9NQVNLLCBHRU5DTEtf RElWKSB8XA0KPiArCQkJCUZJRUxEX1BSRVAoR1BJT19VU0VfU0FNUExFX0RMWV9NQVNLLHVzZV9z YW1fZGx5KTsNCj4gKwltY2lfd3JpdGVsKGhvc3QsIEdQSU8sICh1bnNpZ25lZCBpbnQpcmVnX3Zh bHVlIHwgR1BJT19DTEtfRU5BQkxFKTsNCj4gKw0KPiArCS8qIFdlIHNob3VsZCBkZWxheSAxbXMg d2FpdCBmb3IgdGltaW5nIHNldHRpbmcgZmluaXNoZWQuICovDQo+ICsJdXNsZWVwX3JhbmdlKDEw MDAsIDIwMDApOw0KPiArfQ0KPiArDQo+ICtpbnQgZHdfbWNpX2hpMzY2MF9pbml0KHN0cnVjdCBk d19tY2kgKmhvc3QpIHsNCj4gKwkvKiBzZXQgdGhyZXNob2xkIHRvIDUxMiBieXRlcyAqLw0KPiAr CW1jaV93cml0ZWwoaG9zdCwgQ0RUSFJDVEwsIDB4MDIwMDAwMDEpOw0KPiArDQo+ICsJZHdfbWNp X2hzX3NldF90aW1pbmcoaG9zdCwgTU1DX1RJTUlOR19MRUdBQ1ksIC0xKTsNCj4gKwlob3N0LT5i dXNfaHogLz0gKEdFTkNMS19ESVYgKyAxKTsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiAr DQo+ICtzdGF0aWMgaW50IGR3X21jaV9zZXRfc2VsMTgoc3RydWN0IGR3X21jaSAqaG9zdCwgYm9v bCBzZXQpIHsNCj4gKwlpbnQgcmV0Ow0KPiArCXVuc2lnbmVkIGludCB2YWw7DQo+ICsJc3RydWN0 IGszX3ByaXYgKnByaXY7DQo+ICsNCj4gKwlwcml2ID0gaG9zdC0+cHJpdjsNCj4gKw0KPiArCXZh bCA9IHNldCA/IFNEQ0FSRF9JT19TRUwxOCA6IDA7DQo+ICsJcmV0ID0gcmVnbWFwX3VwZGF0ZV9i aXRzKHByaXYtPnJlZywgU09DX1NDVFJMX1NDUEVSQ1RSTDUsDQo+ICsJCQkJIFNEQ0FSRF9JT19T RUwxOCwgdmFsKTsNCj4gKwlpZiAocmV0KSB7DQo+ICsJCWRldl9lcnIoaG9zdC0+ZGV2LCAic2Vs MTggJXUgZXJyb3JcbiIsIHZhbCk7DQo+ICsJCXJldHVybiByZXQ7DQo+ICsJfQ0KPiArDQo+ICsJ cmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3ZvaWQgZHdfbWNpX2hpMzY2MF9zZXRfaW9zKHN0cnVj dCBkd19tY2kgKmhvc3QsIHN0cnVjdCBtbWNfaW9zICppb3MpIA0KPiArew0KPiArCWludCByZXQ7 DQo+ICsJdW5zaWduZWQgbG9uZyB3YW50ZWQ7DQo+ICsJdW5zaWduZWQgbG9uZyBhY3R1YWw7DQo+ ICsJc3RydWN0IGszX3ByaXYgKnByaXYgPSBob3N0LT5wcml2Ow0KPiArDQo+ICsJaWYgKCFpb3Mt PmNsb2NrIHx8IGlvcy0+Y2xvY2sgPT0gcHJpdi0+Y3VyX3NwZWVkKQ0KPiArCQlyZXR1cm47DQo+ ICsNCj4gKwl3YW50ZWQgPSBpb3MtPmNsb2NrICogKEdFTkNMS19ESVYgKyAxKTsNCj4gKwlyZXQg PSBjbGtfc2V0X3JhdGUoaG9zdC0+Y2l1X2Nsaywgd2FudGVkKTsNCj4gKwlpZiAocmV0KSB7DQo+ ICsJCWRldl9lcnIoaG9zdC0+ZGV2LCAiZmFpbGVkIHRvIHNldCByYXRlICVsdUh6XG4iLCB3YW50 ZWQpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0KPiArCWFjdHVhbCA9IGNsa19nZXRfcmF0ZShob3N0 LT5jaXVfY2xrKTsNCj4gKw0KPiArCWR3X21jaV9oc19zZXRfdGltaW5nKGhvc3QsIGlvcy0+dGlt aW5nLCAtMSk7DQo+ICsJaG9zdC0+YnVzX2h6ID0gYWN0dWFsIC8gKEdFTkNMS19ESVYgKyAxKTsN Cj4gKwlob3N0LT5jdXJyZW50X3NwZWVkID0gMDsNCj4gKwlwcml2LT5jdXJfc3BlZWQgPSBob3N0 LT5idXNfaHo7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgZHdfbWNpX2dldF9iZXN0X2Nsa3Nt cGwodW5zaWduZWQgaW50IHNhbXBsZV9mbGFnKSB7DQo+ICsJaW50IGk7DQo+ICsJaW50IGludGVy dmFsOw0KPiArCXVuc2lnbmVkIGludCB2Ow0KPiArCXVuc2lnbmVkIGludCBsZW47DQo+ICsJdW5z aWduZWQgaW50IHJhbmdlX3N0YXJ0ID0gMDsNCj4gKwl1bnNpZ25lZCBpbnQgcmFuZ2VfbGVuZ3Ro ID0gMDsNCj4gKwl1bnNpZ25lZCBpbnQgbWlkZGxlX3JhbmdlID0gMDsNCj4gKw0KPiArCWlmICgh c2FtcGxlX2ZsYWcpDQo+ICsJCXJldHVybiAtRUlPOw0KPiArDQo+ICsJaWYgKH5zYW1wbGVfZmxh ZyA9PSAwKQ0KPiArCQlyZXR1cm4gMDsNCj4gKw0KPiArCWkgPSBmZnMoc2FtcGxlX2ZsYWcpIC0g MTsNCj4gKw0KPiArCS8qQSBjbG9jayBjeWNsZSBpcyBkaXZpZGVkIGludG8gMzIgcGhhc2VzLCAN Cj4gKwkqZWFjaCBvZiB3aGljaCBpcyByZXByZXNlbnRlZCBieSBhIGJpdCwgZmluZGluZyB0aGUg b3B0aW1hbCBwaGFzZS4NCj4gKwkqLw0KPiArCXdoaWxlIChpIDwgMzIpIHsNCj4gKwkJdiA9IHJv cjMyKHNhbXBsZV9mbGFnLCBpKTsNCj4gKwkJbGVuID0gZmZzKH52KSAtIDE7DQo+ICsNCj4gKwkJ aWYgKGxlbiA+IHJhbmdlX2xlbmd0aCkgew0KPiArCQkJcmFuZ2VfbGVuZ3RoID0gbGVuOw0KPiAr CQkJcmFuZ2Vfc3RhcnQgPSBpOw0KPiArCQl9DQo+ICsNCj4gKwkJaW50ZXJ2YWwgPSBmZnModiA+ PiBsZW4pIC0gMTsNCj4gKwkJaWYgKGludGVydmFsIDwgMCkNCj4gKwkJCWJyZWFrOw0KPiArDQo+ ICsJCWkgKz0gbGVuICsgaW50ZXJ2YWw7DQo+ICsJfQ0KPiArDQo+ICsJbWlkZGxlX3JhbmdlID0g cmFuZ2Vfc3RhcnQgKyByYW5nZV9sZW5ndGggLyAyOw0KPiArCWlmIChtaWRkbGVfcmFuZ2UgPj0g MzIpDQo+ICsJCW1pZGRsZV9yYW5nZSAlPSAzMjsNCj4gKw0KPiArCXJldHVybiBtaWRkbGVfcmFu Z2U7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgZHdfbWNpX2hpMzY2MF9leGVjdXRlX3R1bmlu ZyhzdHJ1Y3QgZHdfbWNpX3Nsb3QgKnNsb3QsIHUzMiANCj4gK29wY29kZSkgew0KPiArCWludCBp ID0gMDsNCj4gKwlzdHJ1Y3QgZHdfbWNpICpob3N0ID0gc2xvdC0+aG9zdDsNCj4gKwlzdHJ1Y3Qg bW1jX2hvc3QgKm1tYyA9IHNsb3QtPm1tYzsNCj4gKwlpbnQgc2FtX3BoYXNlID0gMDsNCj4gKwl1 MzIgdHVuaW5nX3NhbXBsZV9mbGFnID0gMDsNCj4gKwlpbnQgYmVzdF9jbGtzbXBsID0gMDsNCj4g Kw0KPiArCWZvciAoaSA9IDA7IGkgPCBOVU1fUEhBU0VTOyArK2ksICsrc2FtX3BoYXNlKSB7DQo+ ICsJCXNhbV9waGFzZSAlPSAzMjsNCj4gKw0KPiArCQltY2lfd3JpdGVsKGhvc3QsIFRNT1VULCB+ MCk7DQo+ICsJCWR3X21jaV9oc19zZXRfdGltaW5nKGhvc3QsIG1tYy0+aW9zLnRpbWluZywgc2Ft X3BoYXNlKTsNCj4gKw0KPiArCQlpZiAoIW1tY19zZW5kX3R1bmluZyhtbWMsIG9wY29kZSwgTlVM TCkpDQo+ICsJCQl0dW5pbmdfc2FtcGxlX2ZsYWcgfD0gKDEgPDwgc2FtX3BoYXNlKTsNCj4gKwkJ ZWxzZQ0KPiArCQkJdHVuaW5nX3NhbXBsZV9mbGFnICY9IH4oMSA8PCBzYW1fcGhhc2UpOw0KPiAr CX0NCj4gKw0KPiArCWJlc3RfY2xrc21wbCA9IGR3X21jaV9nZXRfYmVzdF9jbGtzbXBsKHR1bmlu Z19zYW1wbGVfZmxhZyk7DQo+ICsJaWYgKGJlc3RfY2xrc21wbCA8IDApIHsNCj4gKwkJZGV2X2Vy cihob3N0LT5kZXYsICJBbGwgcGhhc2VzIGJhZCFcbiIpOw0KPiArCQlyZXR1cm4gLUVJTzsNCj4g Kwl9DQo+ICsNCj4gKwlkd19tY2lfaHNfc2V0X3RpbWluZyhob3N0LCBtbWMtPmlvcy50aW1pbmcs IGJlc3RfY2xrc21wbCk7DQo+ICsNCj4gKwlkZXZfaW5mbyhob3N0LT5kZXYsICJ0dW5pbmcgb2sg YmVzdF9jbGtzbXBsICV1IHR1bmluZ19zYW1wbGVfZmxhZyAleFxuIiwNCj4gKwkJIGJlc3RfY2xr c21wbCwgdHVuaW5nX3NhbXBsZV9mbGFnKTsNCj4gKwlyZXR1cm4gMDsNCj4gK30NCj4gKw0KPiAr c3RhdGljIGludCBkd19tY2lfaGkzNjYwX3N3aXRjaF92b2x0YWdlKHN0cnVjdCBtbWNfaG9zdCAq bW1jLA0KPiArCQkJCQlzdHJ1Y3QgbW1jX2lvcyAqaW9zKQ0KPiArew0KPiArCWludCByZXQ7DQo+ ICsJaW50IG1pbl91diA9IDA7DQo+ICsJaW50IG1heF91diA9IDA7DQo+ICsJc3RydWN0IGR3X21j aV9zbG90ICpzbG90ID0gbW1jX3ByaXYobW1jKTsNCj4gKwlzdHJ1Y3QgazNfcHJpdiAqcHJpdjsN Cj4gKwlzdHJ1Y3QgZHdfbWNpICpob3N0Ow0KPiArDQo+ICsJaG9zdCA9IHNsb3QtPmhvc3Q7DQo+ ICsJcHJpdiA9IGhvc3QtPnByaXY7DQo+ICsNCj4gKwlpZiAoIXByaXYgfHwgIXByaXYtPnJlZykN Cj4gKwkJcmV0dXJuIDA7DQo+ICsNCj4gKwlpZiAocHJpdi0+Y3RybF9pZCA9PSBEV01NQ19TRElP X0lEKQ0KPiArCQlyZXR1cm4gMDsNCj4gKw0KPiArCWlmIChpb3MtPnNpZ25hbF92b2x0YWdlID09 IE1NQ19TSUdOQUxfVk9MVEFHRV8zMzApIHsNCj4gKwkJcmV0ID0gZHdfbWNpX3NldF9zZWwxOCho b3N0LCAwKTsNCj4gKwkJaWYgKHJldCkNCj4gKwkJCXJldHVybiByZXQ7DQo+ICsJCW1pbl91diA9 IDI5NTAwMDA7DQo+ICsJCW1heF91diA9IDI5NTAwMDA7DQo+ICsJfSBlbHNlIGlmIChpb3MtPnNp Z25hbF92b2x0YWdlID09IE1NQ19TSUdOQUxfVk9MVEFHRV8xODApIHsNCj4gKwkJcmV0ID0gZHdf bWNpX3NldF9zZWwxOChob3N0LCAxKTsNCj4gKwkJaWYgKHJldCkNCj4gKwkJCXJldHVybiByZXQ7 DQo+ICsJCW1pbl91diA9IDE4MDAwMDA7DQo+ICsJCW1heF91diA9IDE4MDAwMDA7DQo+ICsJfQ0K PiArDQo+ICsJaWYgKElTX0VSUl9PUl9OVUxMKG1tYy0+c3VwcGx5LnZxbW1jKSkNCj4gKwkJcmV0 dXJuIDA7DQo+ICsNCj4gKwlyZXQgPSByZWd1bGF0b3Jfc2V0X3ZvbHRhZ2UobW1jLT5zdXBwbHku dnFtbWMsIG1pbl91diwgbWF4X3V2KTsNCj4gKwlpZiAocmV0KSB7DQo+ICsJCWRldl9kYmcoaG9z dC0+ZGV2LCAiUmVndWxhdG9yIHNldCBlcnJvciAlZDogJWQgLSAlZFxuIiwNCj4gKwkJCXJldCwg bWluX3V2LCBtYXhfdXYpOw0KPiArCQlyZXR1cm4gcmV0Ow0KPiArCX0NCj4gKwlyZXR1cm4gMDsN Cj4gK30NCj4gKw0KPiArc3RhdGljIGNvbnN0IHN0cnVjdCBkd19tY2lfZHJ2X2RhdGEgaGkzNjYw X2RhdGEgPSB7DQo+ICsJLmluaXQgPSBkd19tY2lfaGkzNjYwX2luaXQsDQo+ICsJLnNldF9pb3Mg PSBkd19tY2lfaGkzNjYwX3NldF9pb3MsDQo+ICsJLnBhcnNlX2R0ID0gZHdfbWNpX2hpNjIyMF9w YXJzZV9kdCwNCj4gKwkuZXhlY3V0ZV90dW5pbmcgPSBkd19tY2lfaGkzNjYwX2V4ZWN1dGVfdHVu aW5nLA0KPiArCS5zd2l0Y2hfdm9sdGFnZSAgPSBkd19tY2lfaGkzNjYwX3N3aXRjaF92b2x0YWdl LCB9Ow0KPiArDQo+ICBzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBkd19tY2lfazNf bWF0Y2hbXSA9IHsNCj4gKwl7IC5jb21wYXRpYmxlID0gImhpc2lsaWNvbixoaTM2NjAtZHctbXNo YyIsIC5kYXRhID0gJmhpMzY2MF9kYXRhLCB9LA0KPiAgCXsgLmNvbXBhdGlibGUgPSAiaGlzaWxp Y29uLGhpNDUxMS1kdy1tc2hjIiwgLmRhdGEgPSAmazNfZHJ2X2RhdGEsIH0sDQo+ICAJeyAuY29t cGF0aWJsZSA9ICJoaXNpbGljb24saGk2MjIwLWR3LW1zaGMiLCAuZGF0YSA9ICZoaTYyMjBfZGF0 YSwgfSwNCj4gIAl7fSwNCj4gQEAgLTE1NSw2ICs0NjQsMTEgQEAgc3RhdGljIGludCBkd19tY2lf azNfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSANCj4gKnBkZXYpICB7DQo+ICAJY29uc3Qg c3RydWN0IGR3X21jaV9kcnZfZGF0YSAqZHJ2X2RhdGE7DQo+ICAJY29uc3Qgc3RydWN0IG9mX2Rl dmljZV9pZCAqbWF0Y2g7DQo+ICsJc3RydWN0IHJlc2V0X2NvbnRyb2wJKnJzdDsNCj4gKw0KPiAr CXJzdCA9IGRldm1fcmVzZXRfY29udHJvbF9nZXQoJnBkZXYtPmRldiwgTlVMTCk7DQo+ICsJaWYg KCFJU19FUlIocnN0KSkNCj4gKwkJcmVzZXRfY29udHJvbF9yZXNldChyc3QpOw0KPiAgDQo+ICAJ bWF0Y2ggPSBvZl9tYXRjaF9ub2RlKGR3X21jaV9rM19tYXRjaCwgcGRldi0+ZGV2Lm9mX25vZGUp Ow0KPiAgCWRydl9kYXRhID0gbWF0Y2gtPmRhdGE7DQo+IA0K -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index e38fb0020bb1..a6e13bd83b9f 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -8,6 +8,8 @@ * (at your option) any later version. */ +#include <linux/bitops.h> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/mfd/syscon.h> #include <linux/mmc/host.h> @@ -28,7 +30,40 @@ #define AO_SCTRL_SEL18 BIT(10) #define AO_SCTRL_CTRL3 0x40C +#define DWMMC_SD_ID 1 +#define DWMMC_SDIO_ID 2 + +#define SOC_SCTRL_SCPERCTRL5 (0x314) +#define SDCARD_IO_SEL18 BIT(2) + +#define GENCLK_DIV (7) + +#define GPIO_CLK_ENABLE BIT(16) +#define GPIO_CLK_DIV_MASK GENMASK(11, 8) +#define GPIO_USE_SAMPLE_DLY_MASK GENMASK(13, 13) +#define UHS_REG_EXT_SAMPLE_PHASE_MASK GENMASK(20, 16) +#define UHS_REG_EXT_SAMPLE_DRVPHASE_MASK GENMASK(25, 21) +#define UHS_REG_EXT_SAMPLE_DLY_MASK GENMASK(30, 26) + +#define SDMMC_UHS_REG_EXT 0x108 +#define SDMMC_ENABLE_SHIFT 0x110 + +#define TIMING_MODE 3 +#define TIMING_CFG_NUM 10 + +#define PULL_DOWN BIT(1) +#define PULL_UP BIT(0) + +#define NUM_PHASES (40) + +#define ENABLE_SHIFT_MIN_SMPL (4) +#define ENABLE_SHIFT_MAX_SMPL (12) +#define USE_DLY_MIN_SMPL (11) +#define USE_DLY_MAX_SMPL (14) + struct k3_priv { + u8 ctrl_id; + u32 cur_speed; struct regmap *reg; }; @@ -38,6 +73,41 @@ static unsigned long dw_mci_hi6220_caps[] = { 0 }; +struct hs_timing { + int drv_phase; + int sam_dly; + int sam_phase_max; + int sam_phase_min; +}; + +struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = { + { /* reserved */ }, + { /* SD */ + {7, 0, 15, 15,}, /* 0: LEGACY 400k */ + {6, 0, 4, 4,}, /* 1: MMC_HS */ + {6, 0, 3, 3,}, /* 2: SD_HS */ + {6, 0, 15, 15,}, /* 3: SDR12 */ + {6, 0, 2, 2,}, /* 4: SDR25 */ + {4, 0, 11, 0,}, /* 5: SDR50 */ + {6, 4, 15, 0,}, /* 6: SDR104 */ + {0}, /* 7: DDR50 */ + {0}, /* 8: DDR52 */ + {0}, /* 9: HS200 */ + }, + { /* SDIO */ + {7, 0, 15, 15,}, /* 0: LEGACY 400k */ + {0}, /* 1: MMC_HS */ + {6, 0, 15, 15,}, /* 2: SD_HS */ + {6, 0, 15, 15,}, /* 3: SDR12 */ + {6, 0, 0, 0,}, /* 4: SDR25 */ + {4, 0, 12, 0,}, /* 5: SDR50 */ + {5, 4, 15, 0,}, /* 6: SDR104 */ + {0}, /* 7: DDR50 */ + {0}, /* 8: DDR52 */ + {0}, /* 9: HS200 */ + } +}; + static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) { int ret; @@ -66,6 +136,10 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host) if (IS_ERR(priv->reg)) priv->reg = NULL; + priv->ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); + if (priv->ctrl_id < 0) + priv->ctrl_id = 0; + host->priv = priv; return 0; } @@ -144,7 +218,242 @@ static const struct dw_mci_drv_data hi6220_data = { .execute_tuning = dw_mci_hi6220_execute_tuning, }; +static void dw_mci_hs_set_timing(struct dw_mci *host, int timing, int sam_phase) +{ + int drv_phase; + int sam_dly; + int ctrl_id; + int use_sam_dly = 0; + int enable_shift = 0; + int reg_value; + struct k3_priv *priv; + + priv = host->priv; + ctrl_id = priv->ctrl_id; + + drv_phase = hs_timing_cfg[ctrl_id][timing].drv_phase; + sam_dly = hs_timing_cfg[ctrl_id][timing].sam_dly; + if (sam_phase == -1) + sam_phase = (hs_timing_cfg[ctrl_id][timing].sam_phase_max + + hs_timing_cfg[ctrl_id][timing].sam_phase_min) / 2; + + if (timing == MMC_TIMING_UHS_SDR50 || + timing == MMC_TIMING_UHS_SDR104) { + if (sam_phase >= ENABLE_SHIFT_MIN_SMPL && + sam_phase <= ENABLE_SHIFT_MAX_SMPL) + enable_shift = 1; + } + if (timing == MMC_TIMING_UHS_SDR104) { + if (sam_phase >= USE_DLY_MIN_SMPL && + sam_phase <= USE_DLY_MAX_SMPL) + use_sam_dly = 1; + } + + mci_writel(host, GPIO, 0x0); + usleep_range(5, 10); + + reg_value = FIELD_PREP(UHS_REG_EXT_SAMPLE_PHASE_MASK, sam_phase) |\ + FIELD_PREP(UHS_REG_EXT_SAMPLE_DLY_MASK ,sam_dly) |\ + FIELD_PREP(UHS_REG_EXT_SAMPLE_DRVPHASE_MASK,drv_phase); + mci_writel(host, UHS_REG_EXT, reg_value); + + mci_writel(host, ENABLE_SHIFT, enable_shift); + + reg_value = FIELD_PREP(GPIO_CLK_DIV_MASK, GENCLK_DIV) |\ + FIELD_PREP(GPIO_USE_SAMPLE_DLY_MASK,use_sam_dly); + mci_writel(host, GPIO, (unsigned int)reg_value | GPIO_CLK_ENABLE); + + /* We should delay 1ms wait for timing setting finished. */ + usleep_range(1000, 2000); +} + +int dw_mci_hi3660_init(struct dw_mci *host) +{ + /* set threshold to 512 bytes */ + mci_writel(host, CDTHRCTL, 0x02000001); + + dw_mci_hs_set_timing(host, MMC_TIMING_LEGACY, -1); + host->bus_hz /= (GENCLK_DIV + 1); + + return 0; +} + +static int dw_mci_set_sel18(struct dw_mci *host, bool set) +{ + int ret; + unsigned int val; + struct k3_priv *priv; + + priv = host->priv; + + val = set ? SDCARD_IO_SEL18 : 0; + ret = regmap_update_bits(priv->reg, SOC_SCTRL_SCPERCTRL5, + SDCARD_IO_SEL18, val); + if (ret) { + dev_err(host->dev, "sel18 %u error\n", val); + return ret; + } + + return 0; +} + +void dw_mci_hi3660_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + int ret; + unsigned long wanted; + unsigned long actual; + struct k3_priv *priv = host->priv; + + if (!ios->clock || ios->clock == priv->cur_speed) + return; + + wanted = ios->clock * (GENCLK_DIV + 1); + ret = clk_set_rate(host->ciu_clk, wanted); + if (ret) { + dev_err(host->dev, "failed to set rate %luHz\n", wanted); + return; + } + actual = clk_get_rate(host->ciu_clk); + + dw_mci_hs_set_timing(host, ios->timing, -1); + host->bus_hz = actual / (GENCLK_DIV + 1); + host->current_speed = 0; + priv->cur_speed = host->bus_hz; +} + +static int dw_mci_get_best_clksmpl(unsigned int sample_flag) +{ + int i; + int interval; + unsigned int v; + unsigned int len; + unsigned int range_start = 0; + unsigned int range_length = 0; + unsigned int middle_range = 0; + + if (!sample_flag) + return -EIO; + + if (~sample_flag == 0) + return 0; + + i = ffs(sample_flag) - 1; + + /*A clock cycle is divided into 32 phases, + *each of which is represented by a bit, finding the optimal phase. + */ + while (i < 32) { + v = ror32(sample_flag, i); + len = ffs(~v) - 1; + + if (len > range_length) { + range_length = len; + range_start = i; + } + + interval = ffs(v >> len) - 1; + if (interval < 0) + break; + + i += len + interval; + } + + middle_range = range_start + range_length / 2; + if (middle_range >= 32) + middle_range %= 32; + + return middle_range; +} + +static int dw_mci_hi3660_execute_tuning(struct dw_mci_slot *slot, u32 opcode) +{ + int i = 0; + struct dw_mci *host = slot->host; + struct mmc_host *mmc = slot->mmc; + int sam_phase = 0; + u32 tuning_sample_flag = 0; + int best_clksmpl = 0; + + for (i = 0; i < NUM_PHASES; ++i, ++sam_phase) { + sam_phase %= 32; + + mci_writel(host, TMOUT, ~0); + dw_mci_hs_set_timing(host, mmc->ios.timing, sam_phase); + + if (!mmc_send_tuning(mmc, opcode, NULL)) + tuning_sample_flag |= (1 << sam_phase); + else + tuning_sample_flag &= ~(1 << sam_phase); + } + + best_clksmpl = dw_mci_get_best_clksmpl(tuning_sample_flag); + if (best_clksmpl < 0) { + dev_err(host->dev, "All phases bad!\n"); + return -EIO; + } + + dw_mci_hs_set_timing(host, mmc->ios.timing, best_clksmpl); + + dev_info(host->dev, "tuning ok best_clksmpl %u tuning_sample_flag %x\n", + best_clksmpl, tuning_sample_flag); + return 0; +} + +static int dw_mci_hi3660_switch_voltage(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + int ret; + int min_uv = 0; + int max_uv = 0; + struct dw_mci_slot *slot = mmc_priv(mmc); + struct k3_priv *priv; + struct dw_mci *host; + + host = slot->host; + priv = host->priv; + + if (!priv || !priv->reg) + return 0; + + if (priv->ctrl_id == DWMMC_SDIO_ID) + return 0; + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + ret = dw_mci_set_sel18(host, 0); + if (ret) + return ret; + min_uv = 2950000; + max_uv = 2950000; + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + ret = dw_mci_set_sel18(host, 1); + if (ret) + return ret; + min_uv = 1800000; + max_uv = 1800000; + } + + if (IS_ERR_OR_NULL(mmc->supply.vqmmc)) + return 0; + + ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); + if (ret) { + dev_dbg(host->dev, "Regulator set error %d: %d - %d\n", + ret, min_uv, max_uv); + return ret; + } + return 0; +} + +static const struct dw_mci_drv_data hi3660_data = { + .init = dw_mci_hi3660_init, + .set_ios = dw_mci_hi3660_set_ios, + .parse_dt = dw_mci_hi6220_parse_dt, + .execute_tuning = dw_mci_hi3660_execute_tuning, + .switch_voltage = dw_mci_hi3660_switch_voltage, +}; + static const struct of_device_id dw_mci_k3_match[] = { + { .compatible = "hisilicon,hi3660-dw-mshc", .data = &hi3660_data, }, { .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, }, { .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, }, {}, @@ -155,6 +464,11 @@ static int dw_mci_k3_probe(struct platform_device *pdev) { const struct dw_mci_drv_data *drv_data; const struct of_device_id *match; + struct reset_control *rst; + + rst = devm_reset_control_get(&pdev->dev, NULL); + if (!IS_ERR(rst)) + reset_control_reset(rst); match = of_match_node(dw_mci_k3_match, pdev->dev.of_node); drv_data = match->data;