// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. * Author: Sagy Shih */ #include #include #include #include #include #include #include #include #include #include static struct platform_device *dramc_pdev; static int mr4_v1_init(struct platform_device *pdev, struct mr4_dev_t *mr4_dev_ptr) { struct device_node *dramc_node = pdev->dev.of_node; int ret; mr4_dev_ptr->version = 1; ret = of_property_read_u32_array(dramc_node, "mr4_rg", (unsigned int *)&(mr4_dev_ptr->mr4_rg), 3); return ret; } static int fmeter_v0_init(struct platform_device *pdev, struct fmeter_dev_t *fmeter_dev_ptr) { struct device_node *dramc_node = pdev->dev.of_node; int ret; fmeter_dev_ptr->version = 0; ret = of_property_read_u32(dramc_node, "crystal_freq", &(fmeter_dev_ptr->crystal_freq)); ret |= of_property_read_u32(dramc_node, "shu_of", &(fmeter_dev_ptr->shu_of)); ret |= of_property_read_u32_array(dramc_node, "shu_lv", (unsigned int *)&(fmeter_dev_ptr->shu_lv), 3); ret |= of_property_read_u32_array(dramc_node, "pll_id", (unsigned int *)&(fmeter_dev_ptr->pll_id), 3); ret |= of_property_read_u32_array(dramc_node, "pll_md", (unsigned int *)(fmeter_dev_ptr->pll_md), 6); ret |= of_property_read_u32_array(dramc_node, "sdmpcw", (unsigned int *)(fmeter_dev_ptr->sdmpcw), 6); ret |= of_property_read_u32_array(dramc_node, "prediv", (unsigned int *)(fmeter_dev_ptr->prediv), 6); ret |= of_property_read_u32_array(dramc_node, "posdiv", (unsigned int *)(fmeter_dev_ptr->posdiv), 6); ret |= of_property_read_u32_array(dramc_node, "ckdiv4", (unsigned int *)(fmeter_dev_ptr->ckdiv4), 6); ret |= of_property_read_u32_array(dramc_node, "cldiv2", (unsigned int *)(fmeter_dev_ptr->cldiv2), 6); return ret; } static int fmeter_v1_init(struct platform_device *pdev, struct fmeter_dev_t *fmeter_dev_ptr) { struct device_node *dramc_node = pdev->dev.of_node; int ret; fmeter_dev_ptr->version = 1; ret = of_property_read_u32(dramc_node, "crystal_freq", &(fmeter_dev_ptr->crystal_freq)); ret |= of_property_read_u32(dramc_node, "shu_of", &(fmeter_dev_ptr->shu_of)); ret |= of_property_read_u32_array(dramc_node, "shu_lv", (unsigned int *)&(fmeter_dev_ptr->shu_lv), 3); ret |= of_property_read_u32_array(dramc_node, "pll_id", (unsigned int *)&(fmeter_dev_ptr->pll_id), 3); ret |= of_property_read_u32_array(dramc_node, "pll_md", (unsigned int *)(fmeter_dev_ptr->pll_md), 6); ret |= of_property_read_u32_array(dramc_node, "sdmpcw", (unsigned int *)(fmeter_dev_ptr->sdmpcw), 6); ret |= of_property_read_u32_array(dramc_node, "prediv", (unsigned int *)(fmeter_dev_ptr->prediv), 6); ret |= of_property_read_u32_array(dramc_node, "posdiv", (unsigned int *)(fmeter_dev_ptr->posdiv), 6); ret |= of_property_read_u32_array(dramc_node, "ckdiv4", (unsigned int *)(fmeter_dev_ptr->ckdiv4), 6); ret |= of_property_read_u32_array(dramc_node, "cldiv2", (unsigned int *)(fmeter_dev_ptr->cldiv2), 6); ret |= of_property_read_u32_array(dramc_node, "fbksel", (unsigned int *)(fmeter_dev_ptr->fbksel), 6); ret |= of_property_read_u32_array(dramc_node, "dqopen", (unsigned int *)(fmeter_dev_ptr->dqopen), 6); return ret; } static ssize_t mr_show(struct device_driver *driver, char *buf) { struct dramc_dev_t *dramc_dev_ptr; struct mr_info_t *mr_info_ptr; unsigned int i; ssize_t ret; if (!dramc_pdev) return strlen(buf); dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); mr_info_ptr = dramc_dev_ptr->mr_info_ptr; for (ret = 0, i = 0; i < dramc_dev_ptr->mr_cnt; i++) { ret += snprintf(buf + ret, PAGE_SIZE - ret, "mr%d: 0x%x\n", mr_info_ptr[i].mr_index, mr_info_ptr[i].mr_value); if (ret >= PAGE_SIZE) return strlen(buf); } return strlen(buf); } static ssize_t mr4_show(struct device_driver *driver, char *buf) { struct dramc_dev_t *dramc_dev_ptr; unsigned int i; ssize_t ret; if (!dramc_pdev) return strlen(buf); dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); for (ret = 0, i = 0; i < dramc_dev_ptr->ch_cnt; i++) { ret += snprintf(buf + ret, PAGE_SIZE - ret, "mr4: ch%d 0x%x\n", i, mtk_dramc_get_mr4(i)); if (ret >= PAGE_SIZE) return strlen(buf); } return strlen(buf); } static ssize_t dram_data_rate_show(struct device_driver *driver, char *buf) { return snprintf(buf, PAGE_SIZE, "DRAM data rate = %d\n", mtk_dramc_get_data_rate()); } __weak int mtk_dramc_binning_test(void) { return 0; } static ssize_t binning_test_show(struct device_driver *driver, char *buf) { int ret; ret = mtk_dramc_binning_test(); if (!ret) return snprintf(buf, PAGE_SIZE, "unsupport mem test\n"); else if (ret > 0) return snprintf(buf, PAGE_SIZE, "mem test all pass\n"); else return snprintf(buf, PAGE_SIZE, "mem test failed %d\n", ret); } static DRIVER_ATTR_RO(mr); static DRIVER_ATTR_RO(mr4); static DRIVER_ATTR_RO(dram_data_rate); static DRIVER_ATTR_RO(binning_test); static int dramc_probe(struct platform_device *pdev) { struct device_node *dramc_node = pdev->dev.of_node; struct dramc_dev_t *dramc_dev_ptr; unsigned int mr4_version; unsigned int fmeter_version; struct resource *res; unsigned int i, size; int ret; pr_info("%s: module probe.\n", __func__); dramc_dev_ptr = devm_kmalloc(&pdev->dev, sizeof(struct dramc_dev_t), GFP_KERNEL); if (!dramc_dev_ptr) return -ENOMEM; ret = of_property_read_u32(dramc_node, "dram_type", &(dramc_dev_ptr->dram_type)); if (ret) { pr_err("%s: get dram_type fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "support_ch_cnt", &(dramc_dev_ptr->support_ch_cnt)); if (ret) { pr_err("%s: get support_ch_cnt fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "ch_cnt", &(dramc_dev_ptr->ch_cnt)); if (ret) { pr_err("%s: get ch_cnt fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "rk_cnt", &(dramc_dev_ptr->rk_cnt)); if (ret) { pr_err("%s: get rk_cnt fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "mr_cnt", &(dramc_dev_ptr->mr_cnt)); if (ret) { pr_err("%s: get mr_cnt fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "freq_cnt", &(dramc_dev_ptr->freq_cnt)); if (ret) { pr_err("%s: get freq_cnt fail\n", __func__); return -EINVAL; } ret = of_property_read_u32(dramc_node, "mr4_version", &mr4_version); if (ret) pr_info("%s: not support mr4\n", __func__); else if (mr4_version == 1) { dramc_dev_ptr->mr4_dev_ptr = devm_kmalloc(&pdev->dev, sizeof(struct mr4_dev_t), GFP_KERNEL); if (!(dramc_dev_ptr->mr4_dev_ptr)) return -ENOMEM; ret = mr4_v1_init(pdev, (struct mr4_dev_t *)(dramc_dev_ptr->mr4_dev_ptr)); if (ret) { pr_err("%s: mr4_v1_init fail\n", __func__); return -EINVAL; } } else dramc_dev_ptr->mr4_dev_ptr = NULL; pr_info("%s: %s(%d),%s(%d),%s(%d),%s(%d),%s(%d),%s(%d),%s(%s)\n", __func__, "dram_type", dramc_dev_ptr->dram_type, "support_ch_cnt", dramc_dev_ptr->support_ch_cnt, "ch_cnt", dramc_dev_ptr->ch_cnt, "rk_cnt", dramc_dev_ptr->rk_cnt, "mr_cnt", dramc_dev_ptr->mr_cnt, "freq_cnt", dramc_dev_ptr->freq_cnt, "mr4", (dramc_dev_ptr->mr4_dev_ptr) ? "true" : "false"); size = sizeof(unsigned int) * dramc_dev_ptr->rk_cnt; dramc_dev_ptr->rk_size = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->rk_size)) return -ENOMEM; ret = of_property_read_u32_array(dramc_node, "rk_size", dramc_dev_ptr->rk_size, dramc_dev_ptr->rk_cnt); if (ret) { pr_err("%s: get rk_size fail\n", __func__); return -EINVAL; } size = sizeof(struct mr_info_t) * dramc_dev_ptr->mr_cnt; dramc_dev_ptr->mr_info_ptr = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->mr_info_ptr)) return -ENOMEM; ret = of_property_read_u32_array(dramc_node, "mr", (unsigned int *)dramc_dev_ptr->mr_info_ptr, size >> 2); if (ret) { pr_err("%s: get mr_info fail\n", __func__); return -EINVAL; } for (i = 0; i < dramc_dev_ptr->mr_cnt; i++) pr_info("%s: mr%d(%x)\n", __func__, dramc_dev_ptr->mr_info_ptr[i].mr_index, dramc_dev_ptr->mr_info_ptr[i].mr_value); size = sizeof(unsigned int) * dramc_dev_ptr->freq_cnt; dramc_dev_ptr->freq_step = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->freq_step)) return -ENOMEM; ret = of_property_read_u32_array(dramc_node, "freq_step", dramc_dev_ptr->freq_step, dramc_dev_ptr->freq_cnt); if (ret) { pr_err("%s: get freq_step fail\n", __func__); return -EINVAL; } dramc_dev_ptr->sleep_base = of_iomap(dramc_node, dramc_dev_ptr->support_ch_cnt * 4); if (IS_ERR(dramc_dev_ptr->sleep_base)) { pr_err("%s: unable to map sleep base\n", __func__); return -EINVAL; } size = sizeof(phys_addr_t) * dramc_dev_ptr->support_ch_cnt; dramc_dev_ptr->dramc_chn_base_ao = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->dramc_chn_base_ao)) return -ENOMEM; dramc_dev_ptr->dramc_chn_base_nao = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->dramc_chn_base_nao)) return -ENOMEM; dramc_dev_ptr->ddrphy_chn_base_ao = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->ddrphy_chn_base_ao)) return -ENOMEM; dramc_dev_ptr->ddrphy_chn_base_nao = devm_kmalloc(&pdev->dev, size, GFP_KERNEL); if (!(dramc_dev_ptr->ddrphy_chn_base_nao)) return -ENOMEM; for (i = 0; i < dramc_dev_ptr->support_ch_cnt; i++) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); dramc_dev_ptr->dramc_chn_base_ao[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dramc_dev_ptr->dramc_chn_base_ao[i])) { pr_err("%s: unable to map ch%d DRAMC AO base\n", __func__, i); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, i + dramc_dev_ptr->support_ch_cnt); dramc_dev_ptr->dramc_chn_base_nao[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dramc_dev_ptr->dramc_chn_base_nao[i])) { pr_err("%s: unable to map ch%d DRAMC NAO base\n", __func__, i); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, i + dramc_dev_ptr->support_ch_cnt * 2); dramc_dev_ptr->ddrphy_chn_base_ao[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dramc_dev_ptr->ddrphy_chn_base_ao[i])) { pr_err("%s: unable to map ch%d DDRPHY AO base\n", __func__, i); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, i + dramc_dev_ptr->support_ch_cnt * 3); dramc_dev_ptr->ddrphy_chn_base_nao[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dramc_dev_ptr->ddrphy_chn_base_nao[i])) { pr_err("%s: unable to map ch%d DDRPHY NAO base\n", __func__, i); return -EINVAL; } } ret = of_property_read_u32( dramc_node, "fmeter_version", &fmeter_version); if (ret) { pr_err("%s: get fmeter_version fail\n", __func__); return -EINVAL; } pr_info("%s: fmeter_version(%d)\n", __func__, fmeter_version); dramc_dev_ptr->fmeter_dev_ptr = devm_kmalloc(&pdev->dev, sizeof(struct fmeter_dev_t), GFP_KERNEL); if (!(dramc_dev_ptr->fmeter_dev_ptr)) { pr_info("%s: memory alloc fail\n", __func__); return -ENOMEM; } switch (fmeter_version) { case 0: ret = fmeter_v0_init(pdev, dramc_dev_ptr->fmeter_dev_ptr); if (ret) { pr_err("%s: fmeter_v0_init fail\n", __func__); return -EINVAL; } break; case 1: ret = fmeter_v1_init(pdev, dramc_dev_ptr->fmeter_dev_ptr); if (ret) { pr_err("%s: fmeter_v1_init fail\n", __func__); return -EINVAL; } break; default: devm_kfree(&pdev->dev, dramc_dev_ptr->fmeter_dev_ptr); dramc_dev_ptr->fmeter_dev_ptr = NULL; } ret = driver_create_file( pdev->dev.driver, &driver_attr_binning_test); if (ret) { pr_info("%s: fail to create binning_test sysfs\n", __func__); return ret; } ret = driver_create_file( pdev->dev.driver, &driver_attr_dram_data_rate); if (ret) { pr_err("%s: fail to create dram_data_rate sysfs\n", __func__); return ret; } ret = driver_create_file( pdev->dev.driver, &driver_attr_mr); if (ret) { pr_err("%s: fail to create mr sysfs\n", __func__); return ret; } if (dramc_dev_ptr->mr4_dev_ptr) { ret = driver_create_file( pdev->dev.driver, &driver_attr_mr4); if (ret) { pr_err("%s: fail to create mr4 sysfs\n", __func__); return ret; } } platform_set_drvdata(pdev, dramc_dev_ptr); dramc_pdev = pdev; pr_info("%s: DRAM data type = %d\n", __func__, mtk_dramc_get_ddr_type()); pr_info("%s: DRAM data rate = %d\n", __func__, mtk_dramc_get_data_rate()); return ret; } static int dramc_remove(struct platform_device *dev) { return 0; } static const struct of_device_id dramc_of_ids[] = { {.compatible = "mediatek,common-dramc",}, {} }; static struct platform_driver dramc_drv = { .probe = dramc_probe, .remove = dramc_remove, .driver = { .name = "dramc_drv", .owner = THIS_MODULE, .of_match_table = dramc_of_ids, }, }; static int __init dramc_drv_init(void) { int ret; ret = platform_driver_register(&dramc_drv); if (ret) { pr_err("%s: init fail, ret 0x%x\n", __func__, ret); return ret; } return ret; } static void __exit dramc_drv_exit(void) { platform_driver_unregister(&dramc_drv); } module_init(dramc_drv_init); module_exit(dramc_drv_exit); /* * mtk_dramc_get_steps_freq - get the freq of target DVFS step * @step: the step index of DVFS * * Returns the DRAM freq */ int mtk_dramc_get_steps_freq(unsigned int step) { struct dramc_dev_t *dramc_dev_ptr; if (!dramc_pdev) return -1; dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); if (step < dramc_dev_ptr->freq_cnt) return dramc_dev_ptr->freq_step[step]; return -1; } EXPORT_SYMBOL(mtk_dramc_get_steps_freq); static unsigned int decode_freq(unsigned int vco_freq) { switch (vco_freq) { case 4264: return 4266; case 3718: return 3733; case 3094: case 3068: return 3200; case 2392: case 2366: return 2400; case 1859: return 1866; case 1534: return 1600; case 1196: case 1144: return 1200; case 819: case 754: return 800; } return vco_freq; } static unsigned int fmeter_v0(struct dramc_dev_t *dramc_dev_ptr) { struct fmeter_dev_t *fmeter_dev_ptr = (struct fmeter_dev_t *)dramc_dev_ptr->fmeter_dev_ptr; unsigned int shu_lv_val; unsigned int pll_id_val; unsigned int pll_md_val; unsigned int sdmpcw_val; unsigned int prediv_val; unsigned int posdiv_val; unsigned int ckdiv4_val; unsigned int cldiv2_val; unsigned int offset; unsigned int vco_freq; shu_lv_val = (readl(dramc_dev_ptr->dramc_chn_base_ao[0] + fmeter_dev_ptr->shu_lv.offset) & fmeter_dev_ptr->shu_lv.mask) >> fmeter_dev_ptr->shu_lv.shift; pll_id_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + fmeter_dev_ptr->pll_id.offset) & fmeter_dev_ptr->pll_id.mask) >> fmeter_dev_ptr->pll_id.shift; offset = fmeter_dev_ptr->pll_md[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; pll_md_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->pll_md[pll_id_val].mask) >> fmeter_dev_ptr->pll_md[pll_id_val].shift; offset = fmeter_dev_ptr->sdmpcw[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; sdmpcw_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->sdmpcw[pll_id_val].mask) >> fmeter_dev_ptr->sdmpcw[pll_id_val].shift; offset = fmeter_dev_ptr->prediv[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; prediv_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->prediv[pll_id_val].mask) >> fmeter_dev_ptr->prediv[pll_id_val].shift; offset = fmeter_dev_ptr->posdiv[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; posdiv_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->posdiv[pll_id_val].mask) >> fmeter_dev_ptr->posdiv[pll_id_val].shift; offset = fmeter_dev_ptr->ckdiv4[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; ckdiv4_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->ckdiv4[pll_id_val].mask) >> fmeter_dev_ptr->ckdiv4[pll_id_val].shift; offset = fmeter_dev_ptr->cldiv2[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; cldiv2_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->cldiv2[pll_id_val].mask) >> fmeter_dev_ptr->cldiv2[pll_id_val].shift; vco_freq = ((fmeter_dev_ptr->crystal_freq >> prediv_val) * (sdmpcw_val >> 8)) >> posdiv_val >> ckdiv4_val >> pll_md_val >> cldiv2_val; return decode_freq(vco_freq); } static unsigned int fmeter_v1(struct dramc_dev_t *dramc_dev_ptr) { struct fmeter_dev_t *fmeter_dev_ptr = (struct fmeter_dev_t *)dramc_dev_ptr->fmeter_dev_ptr; unsigned int shu_lv_val; unsigned int pll_id_val; unsigned int pll_md_val; unsigned int sdmpcw_val; unsigned int prediv_val; unsigned int posdiv_val; unsigned int ckdiv4_val; unsigned int cldiv2_val; unsigned int offset; unsigned int vco_freq; unsigned int fbksel; unsigned int dqopen; shu_lv_val = (readl(dramc_dev_ptr->ddrphy_chn_base_nao[0] + fmeter_dev_ptr->shu_lv.offset) & fmeter_dev_ptr->shu_lv.mask) >> fmeter_dev_ptr->shu_lv.shift; pll_id_val = (readl(dramc_dev_ptr->ddrphy_chn_base_nao[0] + fmeter_dev_ptr->pll_id.offset) & fmeter_dev_ptr->pll_id.mask) >> fmeter_dev_ptr->pll_id.shift; offset = fmeter_dev_ptr->pll_md[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; pll_md_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->pll_md[pll_id_val].mask) >> fmeter_dev_ptr->pll_md[pll_id_val].shift; offset = fmeter_dev_ptr->sdmpcw[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; sdmpcw_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->sdmpcw[pll_id_val].mask) >> fmeter_dev_ptr->sdmpcw[pll_id_val].shift; offset = fmeter_dev_ptr->prediv[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; prediv_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->prediv[pll_id_val].mask) >> fmeter_dev_ptr->prediv[pll_id_val].shift; offset = fmeter_dev_ptr->posdiv[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; posdiv_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->posdiv[pll_id_val].mask) >> fmeter_dev_ptr->posdiv[pll_id_val].shift; offset = fmeter_dev_ptr->ckdiv4[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; ckdiv4_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->ckdiv4[pll_id_val].mask) >> fmeter_dev_ptr->ckdiv4[pll_id_val].shift; offset = fmeter_dev_ptr->cldiv2[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; cldiv2_val = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->cldiv2[pll_id_val].mask) >> fmeter_dev_ptr->cldiv2[pll_id_val].shift; offset = fmeter_dev_ptr->fbksel[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; fbksel = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->fbksel[pll_id_val].mask) >> fmeter_dev_ptr->fbksel[pll_id_val].shift; offset = fmeter_dev_ptr->dqopen[pll_id_val].offset + fmeter_dev_ptr->shu_of * shu_lv_val; dqopen = (readl(dramc_dev_ptr->ddrphy_chn_base_ao[0] + offset) & fmeter_dev_ptr->dqopen[pll_id_val].mask) >> fmeter_dev_ptr->dqopen[pll_id_val].shift; vco_freq = ((fmeter_dev_ptr->crystal_freq >> prediv_val) * (sdmpcw_val >> 8)) >> posdiv_val >> ckdiv4_val >> pll_md_val >> cldiv2_val << fbksel >> (dqopen << 1); return decode_freq(vco_freq); } /* * mtk_dramc_get_data_rate - calculate DRAM data rate * * Returns DRAM data rate (MB/s) */ unsigned int mtk_dramc_get_data_rate(void) { struct dramc_dev_t *dramc_dev_ptr; struct fmeter_dev_t *fmeter_dev_ptr; if (!dramc_pdev) return 0; dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); fmeter_dev_ptr = (struct fmeter_dev_t *)dramc_dev_ptr->fmeter_dev_ptr; if (!fmeter_dev_ptr) return 0; switch (fmeter_dev_ptr->version) { case 0: return fmeter_v0(dramc_dev_ptr); case 1: return fmeter_v1(dramc_dev_ptr); } return 0; } EXPORT_SYMBOL(mtk_dramc_get_data_rate); static unsigned int mr4_v1(struct dramc_dev_t *dramc_dev_ptr, unsigned int ch) { struct mr4_dev_t *mr4_dev_ptr = (struct mr4_dev_t *)dramc_dev_ptr->mr4_dev_ptr; return (readl(dramc_dev_ptr->dramc_chn_base_nao[ch] + mr4_dev_ptr->mr4_rg.offset) & mr4_dev_ptr->mr4_rg.mask) >> mr4_dev_ptr->mr4_rg.shift; } /* * mtk_dramc_get_mr4 - get the DRAM MR4 value of specific DRAM channel * @ch: the channel index * * Returns the MR4 value */ unsigned int mtk_dramc_get_mr4(unsigned int ch) { struct dramc_dev_t *dramc_dev_ptr; struct mr4_dev_t *mr4_dev_ptr; if (!dramc_pdev) return 0; dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); mr4_dev_ptr = (struct mr4_dev_t *)dramc_dev_ptr->mr4_dev_ptr; if (!mr4_dev_ptr) return 0; if (ch >= dramc_dev_ptr->ch_cnt) return 0; if (mr4_dev_ptr->version == 1) return mr4_v1(dramc_dev_ptr, ch); return 0; } EXPORT_SYMBOL(mtk_dramc_get_mr4); /* * mtk_dramc_get_ddr_type - get DRAM type * * Returns the DRAM type */ unsigned int mtk_dramc_get_ddr_type(void) { struct dramc_dev_t *dramc_dev_ptr; if (!dramc_pdev) return 0; dramc_dev_ptr = (struct dramc_dev_t *)platform_get_drvdata(dramc_pdev); return dramc_dev_ptr->dram_type; } EXPORT_SYMBOL(mtk_dramc_get_ddr_type); MODULE_DESCRIPTION("MediaTek DRAMC Driver v0.1");