mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-27 21:03:32 +00:00
Memory controller drivers for v6.12
1. Tegra210 EMC: Driver refactoring and rework. 2. Tegra186 EMC: Drop unused function. 3. FSL WEIM: Correct fsl,weim-cs-timing property to properly validate it as an array. 4. TI AEMIF: Drop platform data support. 5. TI EMIF: Switch to of_property_read_bool(). 6. Several cleanups in multiple drivers: TI AEMIF and EMIF, Tegra EMC/MC, Atmel EBI, Samsung Exynos5422 DMC, STM32 FMC2 EBI, OMAP GPMC, PL172 and PL1353 SMC. These are mostly code simplifying around probe() like using - devm_clk_get_enabled(), - dev_err_probe(), - scoped device node handling (cleanup.h), - scoped for each OF child loops, - scoped/guard locks. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmbNxnEQHGtyemtAa2Vy bmVsLm9yZwAKCRDBN2bmhouD14y6D/4j64Gb8oH5YimxYQz/97B9tTsI0wzWoiPX P+pUY1lWDGuN5CwD7LZrBtK2DKk6QJQcQTu7tav5iV0gt1eMYwzHLz+hBuL1TmHH SFqApBh1qxib8dyTuu/IFnwqXPJ9vfRwYqWEnUQ66mDe54qlhnlDVgty5ls9LFlA cSF4VU+ZctZsUlIy1zAQYq/GLaKh7JA4nn8XkbcoVaDVJ7j+dikovMFE6Thcgcn1 55nukbaArxjJk/3bwoUNccNy6hiazxTvBjGkFuS5YhWAcLyJfkBGOPpx0vxMSjl0 n5R+cN/r6dLnNnRXhD6H8ztlq5xWcO1ziUwIOtHCPGgyOcDZ93cKGcHaUiwd5ZlT /afYHQSQupty4ntpqK7OasyXyfniprXC/KUbpiodmi63Q1YGdEJYp6Q42g/1Xj73 XKch3aOshFePdb2QAZuWXISTucu3cQw7iL7j/FJp6spLSR5W/30lEIUwjAcVrPrF V4S2WiwQxqZZQqFtmijnoC76bdLS76MqlRkZlFx0wpM6ILnQgjqLGmENYaMm8rqV myIrc/cQ3LJX0+kKisVdfbHNs1KWVh3s6GCDrvLlUnqRcjrzvTxV1uwkJVcN3U2g OOpsbJYujYzpw4JMdsFK481HE3+gOhN/jYIc0vUooXw3LkKtx4Rk7cPnAmDfju7C AKhEikLr+g== =/0oc -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmbViXcACgkQYKtH/8kJ UifDtw//VhTtafBj9zQgOCUcdUhYVEbVI/CvHsmtFI87b+ovC0JyzJQL/TP0bTcH xrk3pN1/+T1A0hTPR59b93uJVNd082iz0LA+1L5Um6bMf4wziLF8MwPg7oORNVCh dM2B/5UYEdz74lJDda2FThHQ0LBP3to+GzERMOWUN4kQApHiM63q4uU1Lz5O/v/X ULCe6mwAqn8ugW0LmPUiZwXPxYraK/MQniWlK+IfxJuYeRrc4dciSEAwvjt3yG0Q 2yDuIRn2Va6+q0uE9N/gY3Yc2t1idBpnaD/nxFO6jmTk3a+x4zI6fIbvLLvzWBbb aVQlqWoNsvSJ7msNLIZH0O7J2vszRbphiTDRTkT9sHqNnJ4A4szd7C+b5/g3EGsZ LOSVsvEMeVHmNAL9CJEbgA2UtdoPJL5mPIWLaC2XIR6h0eWd3+p56bg4msToLsj/ gkIJkwXjltxjQJ6NfCHfJC3BbbtHYnNeA+xWGbCVVaCEjEu88rnWlRpOKhEKc2cH tWYF13sSGmZqVNDXarItrLL6xCOD30l+QkjO3l8R/gphqfNAS8dXBviDxjxMiwp5 vjA7cUROgu9I5P6sCYFFohBmYWTcH1/Kl4Gks0JAAD48gd8e8LaZP8pyuVP21dEh 9f7e1FhsDKCQYZMq/WCJZR1fGGvD2OZYi+qfo8aTUDbuH9fCK4Q= =W0Pq -----END PGP SIGNATURE----- Merge tag 'memory-controller-drv-6.12' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers Memory controller drivers for v6.12 1. Tegra210 EMC: Driver refactoring and rework. 2. Tegra186 EMC: Drop unused function. 3. FSL WEIM: Correct fsl,weim-cs-timing property to properly validate it as an array. 4. TI AEMIF: Drop platform data support. 5. TI EMIF: Switch to of_property_read_bool(). 6. Several cleanups in multiple drivers: TI AEMIF and EMIF, Tegra EMC/MC, Atmel EBI, Samsung Exynos5422 DMC, STM32 FMC2 EBI, OMAP GPMC, PL172 and PL1353 SMC. These are mostly code simplifying around probe() like using - devm_clk_get_enabled(), - dev_err_probe(), - scoped device node handling (cleanup.h), - scoped for each OF child loops, - scoped/guard locks. * tag 'memory-controller-drv-6.12' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: (35 commits) memory: mtk-smi: Use devm_clk_get_enabled() memory: pl353-smc: simplify with devm_clk_get_enabled() memory: pl353-smc: simplify with dev_err_probe() memory: pl172: simplify with devm_clk_get_enabled() memory: pl172: simplify with dev_err_probe() memory: omap-gpmc: simplify locking with guard() memory: emif: simplify locking with guard() memory: emif: drop unused 'irq_state' member memory: ti-aemif: Revert "memory: ti-aemif: don't needlessly iterate over child nodes" memory: ti-aemif: simplify with scoped for each OF child loop memory: ti-aemif: simplify with dev_err_probe() memory: tegra30-emc: simplify with scoped for each OF child loop memory: tegra20-emc: simplify with scoped for each OF child loop memory: tegra124-emc: simplify with scoped for each OF child loop memory: tegra-mc: simplify with scoped for each OF child loop memory: stm32-fmc2-ebi: simplify with dev_err_probe() memory: stm32-fmc2-ebi: simplify with scoped for each OF child loop memory: samsung: exynos5422-dmc: use scoped device node handling to simplify error paths memory: samsung: exynos5422-dmc: simplify dmc->dev usage memory: atmel-ebi: simplify with scoped for each OF child loop ... Link: https://lore.kernel.org/r/20240827122926.30794-1-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
3a059ee655
18 changed files with 236 additions and 693 deletions
|
@ -134,9 +134,8 @@ allOf:
|
|||
properties:
|
||||
fsl,weim-cs-timing:
|
||||
items:
|
||||
items:
|
||||
- description: CSxU
|
||||
- description: CSxL
|
||||
- description: CSxU
|
||||
- description: CSxL
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -151,10 +150,9 @@ allOf:
|
|||
properties:
|
||||
fsl,weim-cs-timing:
|
||||
items:
|
||||
items:
|
||||
- description: CSCRxU
|
||||
- description: CSCRxL
|
||||
- description: CSCRxA
|
||||
- description: CSCRxU
|
||||
- description: CSCRxL
|
||||
- description: CSCRxA
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -171,13 +169,12 @@ allOf:
|
|||
properties:
|
||||
fsl,weim-cs-timing:
|
||||
items:
|
||||
items:
|
||||
- description: CSxGCR1
|
||||
- description: CSxGCR2
|
||||
- description: CSxRCR1
|
||||
- description: CSxRCR2
|
||||
- description: CSxWCR1
|
||||
- description: CSxWCR2
|
||||
- description: CSxGCR1
|
||||
- description: CSxGCR2
|
||||
- description: CSxRCR1
|
||||
- description: CSxRCR2
|
||||
- description: CSxWCR1
|
||||
- description: CSxWCR2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@ properties:
|
|||
- const: dirmap
|
||||
- const: wbuf
|
||||
|
||||
clocks: true
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
@ -517,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
|
|||
static int atmel_ebi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *child, *np = dev->of_node, *smc_np;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct atmel_ebi *ebi;
|
||||
int ret, reg_cells;
|
||||
struct clk *clk;
|
||||
|
@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev)
|
|||
|
||||
ebi->clk = clk;
|
||||
|
||||
smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
|
||||
struct device_node *smc_np __free(device_node) =
|
||||
of_parse_phandle(dev->of_node, "atmel,smc", 0);
|
||||
|
||||
ebi->smc.regmap = syscon_node_to_regmap(smc_np);
|
||||
if (IS_ERR(ebi->smc.regmap)) {
|
||||
ret = PTR_ERR(ebi->smc.regmap);
|
||||
goto put_node;
|
||||
}
|
||||
if (IS_ERR(ebi->smc.regmap))
|
||||
return PTR_ERR(ebi->smc.regmap);
|
||||
|
||||
ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
|
||||
if (IS_ERR(ebi->smc.layout)) {
|
||||
ret = PTR_ERR(ebi->smc.layout);
|
||||
goto put_node;
|
||||
}
|
||||
if (IS_ERR(ebi->smc.layout))
|
||||
return PTR_ERR(ebi->smc.layout);
|
||||
|
||||
ebi->smc.clk = of_clk_get(smc_np, 0);
|
||||
if (IS_ERR(ebi->smc.clk)) {
|
||||
if (PTR_ERR(ebi->smc.clk) != -ENOENT) {
|
||||
ret = PTR_ERR(ebi->smc.clk);
|
||||
goto put_node;
|
||||
}
|
||||
if (PTR_ERR(ebi->smc.clk) != -ENOENT)
|
||||
return PTR_ERR(ebi->smc.clk);
|
||||
|
||||
ebi->smc.clk = NULL;
|
||||
}
|
||||
of_node_put(smc_np);
|
||||
ret = clk_prepare_enable(ebi->smc.clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -597,7 +592,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
|
|||
|
||||
reg_cells += val;
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
if (!of_property_present(child, "reg"))
|
||||
continue;
|
||||
|
||||
|
@ -607,18 +602,12 @@ static int atmel_ebi_probe(struct platform_device *pdev)
|
|||
child);
|
||||
|
||||
ret = atmel_ebi_dev_disable(ebi, child);
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return of_platform_populate(np, NULL, NULL, dev);
|
||||
|
||||
put_node:
|
||||
of_node_put(smc_np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __maybe_unused int atmel_ebi_resume(struct device *dev)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Aneesh V <aneesh@ti.com>
|
||||
* Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*/
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
|
@ -57,7 +58,6 @@ struct emif_data {
|
|||
u8 temperature_level;
|
||||
u8 lpmode;
|
||||
struct list_head node;
|
||||
unsigned long irq_state;
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
|
||||
|
@ -69,7 +69,6 @@ struct emif_data {
|
|||
|
||||
static struct emif_data *emif1;
|
||||
static DEFINE_SPINLOCK(emif_lock);
|
||||
static unsigned long irq_state;
|
||||
static LIST_HEAD(device_list);
|
||||
|
||||
static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
|
||||
|
@ -523,18 +522,18 @@ static void setup_temperature_sensitive_regs(struct emif_data *emif,
|
|||
static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
|
||||
{
|
||||
u32 old_temp_level;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
irqreturn_t ret;
|
||||
struct emif_custom_configs *custom_configs;
|
||||
|
||||
spin_lock_irqsave(&emif_lock, irq_state);
|
||||
guard(spinlock_irqsave)(&emif_lock);
|
||||
old_temp_level = emif->temperature_level;
|
||||
get_temperature_level(emif);
|
||||
|
||||
if (unlikely(emif->temperature_level == old_temp_level)) {
|
||||
goto out;
|
||||
return IRQ_HANDLED;
|
||||
} else if (!emif->curr_regs) {
|
||||
dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
|
||||
goto out;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
custom_configs = emif->plat_data->custom_configs;
|
||||
|
@ -554,8 +553,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
|
|||
* from thread context
|
||||
*/
|
||||
emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
goto out;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,10 +569,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
|
|||
/* Temperature is going up - handle immediately */
|
||||
setup_temperature_sensitive_regs(emif, emif->curr_regs);
|
||||
do_freq_update();
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&emif_lock, irq_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -617,6 +614,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
|
|||
static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct emif_data *emif = dev_id;
|
||||
unsigned long irq_state;
|
||||
|
||||
if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
|
||||
dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
|
||||
|
@ -864,7 +862,7 @@ static void of_get_custom_configs(struct device_node *np_emif,
|
|||
be32_to_cpup(poll_intvl);
|
||||
}
|
||||
|
||||
if (of_find_property(np_emif, "extended-temp-part", &len))
|
||||
if (of_property_read_bool(np_emif, "extended-temp-part"))
|
||||
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
|
||||
|
||||
if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
|
||||
|
@ -880,13 +878,9 @@ static void of_get_ddr_info(struct device_node *np_emif,
|
|||
struct ddr_device_info *dev_info)
|
||||
{
|
||||
u32 density = 0, io_width = 0;
|
||||
int len;
|
||||
|
||||
if (of_find_property(np_emif, "cs1-used", &len))
|
||||
dev_info->cs1_used = true;
|
||||
|
||||
if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
|
||||
dev_info->cal_resistors_per_cs = true;
|
||||
dev_info->cs1_used = of_property_read_bool(np_emif, "cs1-used");
|
||||
dev_info->cal_resistors_per_cs = of_property_read_bool(np_emif, "cal-resistor-per-cs");
|
||||
|
||||
if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4"))
|
||||
dev_info->type = DDR_TYPE_LPDDR2_S4;
|
||||
|
@ -916,7 +910,6 @@ static struct emif_data *of_get_memory_device_details(
|
|||
struct ddr_device_info *dev_info = NULL;
|
||||
struct emif_platform_data *pd = NULL;
|
||||
struct device_node *np_ddr;
|
||||
int len;
|
||||
|
||||
np_ddr = of_parse_phandle(np_emif, "device-handle", 0);
|
||||
if (!np_ddr)
|
||||
|
@ -944,7 +937,7 @@ static struct emif_data *of_get_memory_device_details(
|
|||
|
||||
of_property_read_u32(np_emif, "phy-type", &pd->phy_type);
|
||||
|
||||
if (of_find_property(np_emif, "hw-caps-ll-interface", &len))
|
||||
if (of_property_read_bool(np_emif, "hw-caps-ll-interface"))
|
||||
pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE;
|
||||
|
||||
of_get_ddr_info(np_emif, np_ddr, dev_info);
|
||||
|
|
|
@ -771,13 +771,9 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(common->smi_ao_base))
|
||||
return PTR_ERR(common->smi_ao_base);
|
||||
|
||||
common->clk_async = devm_clk_get(dev, "async");
|
||||
common->clk_async = devm_clk_get_enabled(dev, "async");
|
||||
if (IS_ERR(common->clk_async))
|
||||
return PTR_ERR(common->clk_async);
|
||||
|
||||
ret = clk_prepare_enable(common->clk_async);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
common->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(common->base))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Copyright (C) 2009 Texas Instruments
|
||||
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*/
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -989,18 +990,18 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
|||
if (size > (1 << GPMC_SECTION_SHIFT))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
if (gpmc_cs_reserved(cs)) {
|
||||
r = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
guard(spinlock)(&gpmc_mem_lock);
|
||||
|
||||
if (gpmc_cs_reserved(cs))
|
||||
return -EBUSY;
|
||||
|
||||
if (gpmc_cs_mem_enabled(cs))
|
||||
r = adjust_resource(res, res->start & ~(size - 1), size);
|
||||
if (r < 0)
|
||||
r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
|
||||
size, NULL, NULL);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
|
||||
/* Disable CS while changing base address and size mask */
|
||||
gpmc_cs_disable_mem(cs);
|
||||
|
@ -1008,16 +1009,15 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
|||
r = gpmc_cs_set_memconf(cs, res->start, resource_size(res));
|
||||
if (r < 0) {
|
||||
release_resource(res);
|
||||
goto out;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Enable CS */
|
||||
gpmc_cs_enable_mem(cs);
|
||||
*base = res->start;
|
||||
gpmc_cs_set_reserved(cs, 1);
|
||||
out:
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_cs_request);
|
||||
|
||||
|
@ -1026,10 +1026,9 @@ void gpmc_cs_free(int cs)
|
|||
struct gpmc_cs_data *gpmc;
|
||||
struct resource *res;
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
guard(spinlock)(&gpmc_mem_lock);
|
||||
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
|
||||
WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs);
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
return;
|
||||
}
|
||||
gpmc = &gpmc_cs[cs];
|
||||
|
@ -1039,7 +1038,6 @@ void gpmc_cs_free(int cs)
|
|||
if (res->flags)
|
||||
release_resource(res);
|
||||
gpmc_cs_set_reserved(cs, 0);
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_cs_free);
|
||||
|
||||
|
|
|
@ -216,29 +216,20 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
if (!pl172)
|
||||
return -ENOMEM;
|
||||
|
||||
pl172->clk = devm_clk_get(dev, "mpmcclk");
|
||||
if (IS_ERR(pl172->clk)) {
|
||||
dev_err(dev, "no mpmcclk provided clock\n");
|
||||
return PTR_ERR(pl172->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pl172->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to mpmcclk enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
pl172->clk = devm_clk_get_enabled(dev, "mpmcclk");
|
||||
if (IS_ERR(pl172->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(pl172->clk),
|
||||
"no mpmcclk provided clock\n");
|
||||
|
||||
pl172->rate = clk_get_rate(pl172->clk) / MSEC_PER_SEC;
|
||||
if (!pl172->rate) {
|
||||
dev_err(dev, "unable to get mpmcclk clock rate\n");
|
||||
ret = -EINVAL;
|
||||
goto err_clk_enable;
|
||||
}
|
||||
if (!pl172->rate)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"unable to get mpmcclk clock rate\n");
|
||||
|
||||
ret = amba_request_regions(adev, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to request AMBA regions\n");
|
||||
goto err_clk_enable;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pl172->base = devm_ioremap(dev, adev->res.start,
|
||||
|
@ -268,16 +259,11 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
|
||||
err_no_ioremap:
|
||||
amba_release_regions(adev);
|
||||
err_clk_enable:
|
||||
clk_disable_unprepare(pl172->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pl172_remove(struct amba_device *adev)
|
||||
{
|
||||
struct pl172_data *pl172 = amba_get_drvdata(adev);
|
||||
|
||||
clk_disable_unprepare(pl172->clk);
|
||||
amba_release_regions(adev);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,35 +75,20 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
const struct of_device_id *match = NULL;
|
||||
struct pl353_smc_data *pl353_smc;
|
||||
struct device_node *child;
|
||||
int err;
|
||||
|
||||
pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL);
|
||||
if (!pl353_smc)
|
||||
return -ENOMEM;
|
||||
|
||||
pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk");
|
||||
if (IS_ERR(pl353_smc->aclk)) {
|
||||
dev_err(&adev->dev, "aclk clock not found.\n");
|
||||
return PTR_ERR(pl353_smc->aclk);
|
||||
}
|
||||
pl353_smc->aclk = devm_clk_get_enabled(&adev->dev, "apb_pclk");
|
||||
if (IS_ERR(pl353_smc->aclk))
|
||||
return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->aclk),
|
||||
"aclk clock not found.\n");
|
||||
|
||||
pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk");
|
||||
if (IS_ERR(pl353_smc->memclk)) {
|
||||
dev_err(&adev->dev, "memclk clock not found.\n");
|
||||
return PTR_ERR(pl353_smc->memclk);
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(pl353_smc->aclk);
|
||||
if (err) {
|
||||
dev_err(&adev->dev, "Unable to enable AXI clock.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(pl353_smc->memclk);
|
||||
if (err) {
|
||||
dev_err(&adev->dev, "Unable to enable memory clock.\n");
|
||||
goto disable_axi_clk;
|
||||
}
|
||||
pl353_smc->memclk = devm_clk_get_enabled(&adev->dev, "memclk");
|
||||
if (IS_ERR(pl353_smc->memclk))
|
||||
return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->memclk),
|
||||
"memclk clock not found.\n");
|
||||
|
||||
amba_set_drvdata(adev, pl353_smc);
|
||||
|
||||
|
@ -117,30 +102,14 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
break;
|
||||
}
|
||||
if (!match) {
|
||||
err = -ENODEV;
|
||||
dev_err(&adev->dev, "no matching children\n");
|
||||
goto disable_mem_clk;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
of_platform_device_create(child, NULL, &adev->dev);
|
||||
of_node_put(child);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_mem_clk:
|
||||
clk_disable_unprepare(pl353_smc->memclk);
|
||||
disable_axi_clk:
|
||||
clk_disable_unprepare(pl353_smc->aclk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pl353_smc_remove(struct amba_device *adev)
|
||||
{
|
||||
struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev);
|
||||
|
||||
clk_disable_unprepare(pl353_smc->memclk);
|
||||
clk_disable_unprepare(pl353_smc->aclk);
|
||||
}
|
||||
|
||||
static const struct amba_id pl353_ids[] = {
|
||||
|
@ -159,7 +128,6 @@ static struct amba_driver pl353_smc_driver = {
|
|||
},
|
||||
.id_table = pl353_ids,
|
||||
.probe = pl353_smc_probe,
|
||||
.remove = pl353_smc_remove,
|
||||
};
|
||||
|
||||
module_amba_driver(pl353_smc_driver);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Author: Lukasz Luba <l.luba@partner.samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/devfreq.h>
|
||||
#include <linux/devfreq-event.h>
|
||||
|
@ -339,19 +340,20 @@ static int exynos5_switch_timing_regs(struct exynos5_dmc *dmc, bool set)
|
|||
static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
||||
struct devfreq_dev_profile *profile)
|
||||
{
|
||||
struct device *dev = dmc->dev;
|
||||
int i, ret;
|
||||
int idx;
|
||||
unsigned long freq;
|
||||
|
||||
ret = devm_pm_opp_of_add_table(dmc->dev);
|
||||
ret = devm_pm_opp_of_add_table(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dmc->dev, "Failed to get OPP table\n");
|
||||
dev_err(dev, "Failed to get OPP table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dmc->opp_count = dev_pm_opp_get_opp_count(dmc->dev);
|
||||
dmc->opp_count = dev_pm_opp_get_opp_count(dev);
|
||||
|
||||
dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count,
|
||||
dmc->opp = devm_kmalloc_array(dev, dmc->opp_count,
|
||||
sizeof(struct dmc_opp_table), GFP_KERNEL);
|
||||
if (!dmc->opp)
|
||||
return -ENOMEM;
|
||||
|
@ -360,7 +362,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
|||
for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) {
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq);
|
||||
opp = dev_pm_opp_find_freq_floor(dev, &freq);
|
||||
if (IS_ERR(opp))
|
||||
return PTR_ERR(opp);
|
||||
|
||||
|
@ -1175,51 +1177,44 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
|
|||
static int of_get_dram_timings(struct exynos5_dmc *dmc)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device *dev = dmc->dev;
|
||||
int idx;
|
||||
struct device_node *np_ddr;
|
||||
u32 freq_mhz, clk_period_ps;
|
||||
|
||||
np_ddr = of_parse_phandle(dmc->dev->of_node, "device-handle", 0);
|
||||
struct device_node *np_ddr __free(device_node) =
|
||||
of_parse_phandle(dev->of_node, "device-handle", 0);
|
||||
if (!np_ddr) {
|
||||
dev_warn(dmc->dev, "could not find 'device-handle' in DT\n");
|
||||
dev_warn(dev, "could not find 'device-handle' in DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
|
||||
dmc->timing_row = devm_kmalloc_array(dev, TIMING_COUNT,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!dmc->timing_row) {
|
||||
ret = -ENOMEM;
|
||||
goto put_node;
|
||||
}
|
||||
if (!dmc->timing_row)
|
||||
return -ENOMEM;
|
||||
|
||||
dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
|
||||
dmc->timing_data = devm_kmalloc_array(dev, TIMING_COUNT,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!dmc->timing_data) {
|
||||
ret = -ENOMEM;
|
||||
goto put_node;
|
||||
}
|
||||
if (!dmc->timing_data)
|
||||
return -ENOMEM;
|
||||
|
||||
dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
|
||||
dmc->timing_power = devm_kmalloc_array(dev, TIMING_COUNT,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!dmc->timing_power) {
|
||||
ret = -ENOMEM;
|
||||
goto put_node;
|
||||
}
|
||||
if (!dmc->timing_power)
|
||||
return -ENOMEM;
|
||||
|
||||
dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev,
|
||||
dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dev,
|
||||
DDR_TYPE_LPDDR3,
|
||||
&dmc->timings_arr_size);
|
||||
if (!dmc->timings) {
|
||||
dev_warn(dmc->dev, "could not get timings from DT\n");
|
||||
ret = -EINVAL;
|
||||
goto put_node;
|
||||
dev_warn(dev, "could not get timings from DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev);
|
||||
dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dev);
|
||||
if (!dmc->min_tck) {
|
||||
dev_warn(dmc->dev, "could not get tck from DT\n");
|
||||
ret = -EINVAL;
|
||||
goto put_node;
|
||||
dev_warn(dev, "could not get tck from DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Sorted array of OPPs with frequency ascending */
|
||||
|
@ -1239,8 +1234,6 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc)
|
|||
dmc->bypass_timing_data = dmc->timing_data[idx - 1];
|
||||
dmc->bypass_timing_power = dmc->timing_power[idx - 1];
|
||||
|
||||
put_node:
|
||||
of_node_put(np_ddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1254,34 +1247,34 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc)
|
|||
static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = dmc->dev;
|
||||
unsigned long target_volt = 0;
|
||||
unsigned long target_rate = 0;
|
||||
unsigned int tmp;
|
||||
|
||||
dmc->fout_spll = devm_clk_get(dmc->dev, "fout_spll");
|
||||
dmc->fout_spll = devm_clk_get(dev, "fout_spll");
|
||||
if (IS_ERR(dmc->fout_spll))
|
||||
return PTR_ERR(dmc->fout_spll);
|
||||
|
||||
dmc->fout_bpll = devm_clk_get(dmc->dev, "fout_bpll");
|
||||
dmc->fout_bpll = devm_clk_get(dev, "fout_bpll");
|
||||
if (IS_ERR(dmc->fout_bpll))
|
||||
return PTR_ERR(dmc->fout_bpll);
|
||||
|
||||
dmc->mout_mclk_cdrex = devm_clk_get(dmc->dev, "mout_mclk_cdrex");
|
||||
dmc->mout_mclk_cdrex = devm_clk_get(dev, "mout_mclk_cdrex");
|
||||
if (IS_ERR(dmc->mout_mclk_cdrex))
|
||||
return PTR_ERR(dmc->mout_mclk_cdrex);
|
||||
|
||||
dmc->mout_bpll = devm_clk_get(dmc->dev, "mout_bpll");
|
||||
dmc->mout_bpll = devm_clk_get(dev, "mout_bpll");
|
||||
if (IS_ERR(dmc->mout_bpll))
|
||||
return PTR_ERR(dmc->mout_bpll);
|
||||
|
||||
dmc->mout_mx_mspll_ccore = devm_clk_get(dmc->dev,
|
||||
"mout_mx_mspll_ccore");
|
||||
dmc->mout_mx_mspll_ccore = devm_clk_get(dev, "mout_mx_mspll_ccore");
|
||||
if (IS_ERR(dmc->mout_mx_mspll_ccore))
|
||||
return PTR_ERR(dmc->mout_mx_mspll_ccore);
|
||||
|
||||
dmc->mout_spll = devm_clk_get(dmc->dev, "ff_dout_spll2");
|
||||
dmc->mout_spll = devm_clk_get(dev, "ff_dout_spll2");
|
||||
if (IS_ERR(dmc->mout_spll)) {
|
||||
dmc->mout_spll = devm_clk_get(dmc->dev, "mout_sclk_spll");
|
||||
dmc->mout_spll = devm_clk_get(dev, "mout_sclk_spll");
|
||||
if (IS_ERR(dmc->mout_spll))
|
||||
return PTR_ERR(dmc->mout_spll);
|
||||
}
|
||||
|
@ -1329,38 +1322,37 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
|
|||
*/
|
||||
static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
|
||||
{
|
||||
struct device *dev = dmc->dev;
|
||||
int ret, i;
|
||||
|
||||
dmc->num_counters = devfreq_event_get_edev_count(dmc->dev,
|
||||
"devfreq-events");
|
||||
dmc->num_counters = devfreq_event_get_edev_count(dev, "devfreq-events");
|
||||
if (dmc->num_counters < 0) {
|
||||
dev_err(dmc->dev, "could not get devfreq-event counters\n");
|
||||
dev_err(dev, "could not get devfreq-event counters\n");
|
||||
return dmc->num_counters;
|
||||
}
|
||||
|
||||
dmc->counter = devm_kcalloc(dmc->dev, dmc->num_counters,
|
||||
dmc->counter = devm_kcalloc(dev, dmc->num_counters,
|
||||
sizeof(*dmc->counter), GFP_KERNEL);
|
||||
if (!dmc->counter)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < dmc->num_counters; i++) {
|
||||
dmc->counter[i] =
|
||||
devfreq_event_get_edev_by_phandle(dmc->dev,
|
||||
"devfreq-events", i);
|
||||
devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i);
|
||||
if (IS_ERR_OR_NULL(dmc->counter[i]))
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = exynos5_counters_enable_edev(dmc);
|
||||
if (ret < 0) {
|
||||
dev_err(dmc->dev, "could not enable event counter\n");
|
||||
dev_err(dev, "could not enable event counter\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = exynos5_counters_set_event(dmc);
|
||||
if (ret < 0) {
|
||||
exynos5_counters_disable_edev(dmc);
|
||||
dev_err(dmc->dev, "could not set event counter\n");
|
||||
dev_err(dev, "could not set event counter\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1573,29 +1573,22 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
|
|||
static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
|
||||
{
|
||||
struct device *dev = ebi->dev;
|
||||
struct device_node *child;
|
||||
bool child_found = false;
|
||||
u32 bank;
|
||||
int ret;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
for_each_available_child_of_node_scoped(dev->of_node, child) {
|
||||
ret = of_property_read_u32(child, "reg", &bank);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not retrieve reg property: %d\n",
|
||||
ret);
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "could not retrieve reg property\n");
|
||||
|
||||
if (bank >= FMC2_MAX_BANKS) {
|
||||
dev_err(dev, "invalid reg value: %d\n", bank);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ebi->bank_assigned & BIT(bank)) {
|
||||
dev_err(dev, "bank already assigned: %d\n", bank);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1603,19 +1596,15 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
|
|||
ret = ebi->data->check_rif(ebi, bank + 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "bank access failed: %d\n", bank);
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (bank < FMC2_MAX_EBI_CE) {
|
||||
ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank);
|
||||
if (ret) {
|
||||
dev_err(dev, "setup chip select %d failed: %d\n",
|
||||
bank, ret);
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"setup chip select %d failed\n", bank);
|
||||
}
|
||||
|
||||
ebi->bank_assigned |= BIT(bank);
|
||||
|
|
|
@ -450,7 +450,6 @@ static int load_one_timing(struct tegra_mc *mc,
|
|||
|
||||
static int load_timings(struct tegra_mc *mc, struct device_node *node)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct tegra_mc_timing *timing;
|
||||
int child_count = of_get_child_count(node);
|
||||
int i = 0, err;
|
||||
|
@ -462,14 +461,12 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node)
|
|||
|
||||
mc->num_timings = child_count;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
for_each_child_of_node_scoped(node, child) {
|
||||
timing = &mc->timings[i++];
|
||||
|
||||
err = load_one_timing(mc, timing, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -477,7 +474,6 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node)
|
|||
|
||||
static int tegra_mc_setup_timings(struct tegra_mc *mc)
|
||||
{
|
||||
struct device_node *node;
|
||||
u32 ram_code, node_ram_code;
|
||||
int err;
|
||||
|
||||
|
@ -485,14 +481,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
|
|||
|
||||
mc->num_timings = 0;
|
||||
|
||||
for_each_child_of_node(mc->dev->of_node, node) {
|
||||
for_each_child_of_node_scoped(mc->dev->of_node, node) {
|
||||
err = of_property_read_u32(node, "nvidia,ram-code",
|
||||
&node_ram_code);
|
||||
if (err || (node_ram_code != ram_code))
|
||||
continue;
|
||||
|
||||
err = load_timings(mc, node);
|
||||
of_node_put(node);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
|
|
@ -992,7 +992,6 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
struct device_node *node)
|
||||
{
|
||||
int child_count = of_get_child_count(node);
|
||||
struct device_node *child;
|
||||
struct emc_timing *timing;
|
||||
unsigned int i = 0;
|
||||
int err;
|
||||
|
@ -1004,14 +1003,12 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
|
||||
emc->num_timings = child_count;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
for_each_child_of_node_scoped(node, child) {
|
||||
timing = &emc->timings[i++];
|
||||
|
||||
err = load_one_timing_from_dt(emc, timing, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
|
||||
|
|
|
@ -35,11 +35,6 @@ struct tegra186_emc {
|
|||
struct icc_provider provider;
|
||||
};
|
||||
|
||||
static inline struct tegra186_emc *to_tegra186_emc(struct icc_provider *provider)
|
||||
{
|
||||
return container_of(provider, struct tegra186_emc, provider);
|
||||
}
|
||||
|
||||
/*
|
||||
* debugfs interface
|
||||
*
|
||||
|
|
|
@ -410,7 +410,6 @@ static int cmp_timings(const void *_a, const void *_b)
|
|||
static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct emc_timing *timing;
|
||||
int child_count;
|
||||
int err;
|
||||
|
@ -428,15 +427,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
|
||||
timing = emc->timings;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
for_each_child_of_node_scoped(node, child) {
|
||||
if (of_node_name_eq(child, "lpddr2"))
|
||||
continue;
|
||||
|
||||
err = load_one_timing_from_dt(emc, timing++, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->num_timings++;
|
||||
}
|
||||
|
|
|
@ -75,29 +75,29 @@ enum {
|
|||
* The division portion of the average operation.
|
||||
*/
|
||||
#define __AVERAGE_PTFV(dev) \
|
||||
({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] = \
|
||||
next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
|
||||
({ next->ptfv_list[(dev)] = \
|
||||
next->ptfv_list[(dev)] / \
|
||||
next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
|
||||
|
||||
/*
|
||||
* Convert val to fixed point and add it to the temporary average.
|
||||
*/
|
||||
#define __INCREMENT_PTFV(dev, val) \
|
||||
({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] += \
|
||||
({ next->ptfv_list[(dev)] += \
|
||||
((val) * MOVAVG_PRECISION_FACTOR); })
|
||||
|
||||
/*
|
||||
* Convert a moving average back to integral form and return the value.
|
||||
*/
|
||||
#define __MOVAVG_AC(timing, dev) \
|
||||
((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
|
||||
((timing)->ptfv_list[(dev)] / \
|
||||
MOVAVG_PRECISION_FACTOR)
|
||||
|
||||
/* Weighted update. */
|
||||
#define __WEIGHTED_UPDATE_PTFV(dev, nval) \
|
||||
do { \
|
||||
int w = PTFV_MOVAVG_WEIGHT_INDEX; \
|
||||
int dqs = PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX; \
|
||||
int dqs = (dev); \
|
||||
\
|
||||
next->ptfv_list[dqs] = \
|
||||
((nval * MOVAVG_PRECISION_FACTOR) + \
|
||||
|
@ -105,315 +105,91 @@ enum {
|
|||
next->ptfv_list[w])) / \
|
||||
(next->ptfv_list[w] + 1); \
|
||||
\
|
||||
emc_dbg(emc, EMA_UPDATES, "%s: (s=%lu) EMA: %u\n", \
|
||||
emc_dbg(emc, EMA_UPDATES, "%s: (s=%u) EMA: %u\n", \
|
||||
__stringify(dev), nval, next->ptfv_list[dqs]); \
|
||||
} while (0)
|
||||
|
||||
/* Access a particular average. */
|
||||
#define __MOVAVG(timing, dev) \
|
||||
((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX])
|
||||
((timing)->ptfv_list[(dev)])
|
||||
|
||||
static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type)
|
||||
static bool tegra210_emc_compare_update_delay(struct tegra210_emc_timing *timing,
|
||||
u32 measured, u32 idx)
|
||||
{
|
||||
bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE;
|
||||
struct tegra210_emc_timing *last = emc->last;
|
||||
struct tegra210_emc_timing *next = emc->next;
|
||||
u32 last_timing_rate_mhz = last->rate / 1000;
|
||||
u32 next_timing_rate_mhz = next->rate / 1000;
|
||||
bool dvfs_update = type == DVFS_UPDATE;
|
||||
s32 tdel = 0, tmdel = 0, adel = 0;
|
||||
bool dvfs_pt1 = type == DVFS_PT1;
|
||||
unsigned long cval = 0;
|
||||
u32 temp[2][2], value;
|
||||
unsigned int i;
|
||||
u32 *curr = &timing->current_dram_clktree[idx];
|
||||
u32 rate_mhz = timing->rate / 1000;
|
||||
u32 tmdel;
|
||||
|
||||
/*
|
||||
* Dev0 MSB.
|
||||
*/
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
value = tegra210_emc_mrr_read(emc, 2, 19);
|
||||
tmdel = abs(*curr - measured);
|
||||
|
||||
for (i = 0; i < emc->num_channels; i++) {
|
||||
temp[i][0] = (value & 0x00ff) << 8;
|
||||
temp[i][1] = (value & 0xff00) << 0;
|
||||
value >>= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dev0 LSB.
|
||||
*/
|
||||
value = tegra210_emc_mrr_read(emc, 2, 18);
|
||||
|
||||
for (i = 0; i < emc->num_channels; i++) {
|
||||
temp[i][0] |= (value & 0x00ff) >> 0;
|
||||
temp[i][1] |= (value & 0xff00) >> 8;
|
||||
value >>= 16;
|
||||
}
|
||||
if (tmdel * 128 * rate_mhz / 1000000 > timing->tree_margin) {
|
||||
*curr = measured;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[0][0];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C0D0U0, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C0D0U0);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C0D0U0, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C0D0U0] -
|
||||
__MOVAVG_AC(next, C0D0U0);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C0D0U0] =
|
||||
__MOVAVG_AC(next, C0D0U0);
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[0][1];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C0D0U1, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C0D0U1);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C0D0U1, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C0D0U1] -
|
||||
__MOVAVG_AC(next, C0D0U1);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C0D0U1] =
|
||||
__MOVAVG_AC(next, C0D0U1);
|
||||
}
|
||||
|
||||
if (emc->num_channels > 1) {
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[1][0];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C1D0U0, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C1D0U0);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C1D0U0, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C1D0U0] -
|
||||
__MOVAVG_AC(next, C1D0U0);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C1D0U0] =
|
||||
__MOVAVG_AC(next, C1D0U0);
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[1][1];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C1D0U1, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C1D0U1);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C1D0U1, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C1D0U1] -
|
||||
__MOVAVG_AC(next, C1D0U1);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C1D0U1] =
|
||||
__MOVAVG_AC(next, C1D0U1);
|
||||
}
|
||||
}
|
||||
|
||||
if (emc->num_devices < 2)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Dev1 MSB.
|
||||
*/
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
value = tegra210_emc_mrr_read(emc, 1, 19);
|
||||
|
||||
for (i = 0; i < emc->num_channels; i++) {
|
||||
temp[i][0] = (value & 0x00ff) << 8;
|
||||
temp[i][1] = (value & 0xff00) << 0;
|
||||
value >>= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dev1 LSB.
|
||||
*/
|
||||
value = tegra210_emc_mrr_read(emc, 1, 18);
|
||||
|
||||
for (i = 0; i < emc->num_channels; i++) {
|
||||
temp[i][0] |= (value & 0x00ff) >> 0;
|
||||
temp[i][1] |= (value & 0xff00) >> 8;
|
||||
value >>= 16;
|
||||
}
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[0][0];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C0D1U0, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C0D1U0);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C0D1U0, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C0D1U0] -
|
||||
__MOVAVG_AC(next, C0D1U0);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C0D1U0] =
|
||||
__MOVAVG_AC(next, C0D1U0);
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[0][1];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C0D1U1, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C0D1U1);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C0D1U1, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C0D1U1] -
|
||||
__MOVAVG_AC(next, C0D1U1);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C0D1U1] =
|
||||
__MOVAVG_AC(next, C0D1U1);
|
||||
}
|
||||
|
||||
if (emc->num_channels > 1) {
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[1][0];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C1D1U0, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C1D1U0);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C1D1U0, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C1D1U0] -
|
||||
__MOVAVG_AC(next, C1D1U0);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C1D1U0] =
|
||||
__MOVAVG_AC(next, C1D1U0);
|
||||
}
|
||||
|
||||
if (dvfs_pt1 || periodic_training_update) {
|
||||
cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
cval *= 1000000;
|
||||
cval /= last_timing_rate_mhz * 2 * temp[1][1];
|
||||
}
|
||||
|
||||
if (dvfs_pt1)
|
||||
__INCREMENT_PTFV(C1D1U1, cval);
|
||||
else if (dvfs_update)
|
||||
__AVERAGE_PTFV(C1D1U1);
|
||||
else if (periodic_training_update)
|
||||
__WEIGHTED_UPDATE_PTFV(C1D1U1, cval);
|
||||
|
||||
if (dvfs_update || periodic_training_update) {
|
||||
tdel = next->current_dram_clktree[C1D1U1] -
|
||||
__MOVAVG_AC(next, C1D1U1);
|
||||
tmdel = (tdel < 0) ? -1 * tdel : tdel;
|
||||
|
||||
if (tmdel > adel)
|
||||
adel = tmdel;
|
||||
|
||||
if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
|
||||
next->tree_margin)
|
||||
next->current_dram_clktree[C1D1U1] =
|
||||
__MOVAVG_AC(next, C1D1U1);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return adel;
|
||||
return false;
|
||||
}
|
||||
|
||||
static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
|
||||
struct tegra210_emc_timing *last,
|
||||
struct tegra210_emc_timing *next)
|
||||
static void tegra210_emc_get_clktree_delay(struct tegra210_emc *emc,
|
||||
u32 delay[DRAM_CLKTREE_NUM])
|
||||
{
|
||||
struct tegra210_emc_timing *curr = emc->last;
|
||||
u32 rate_mhz = curr->rate / 1000;
|
||||
u32 msb, lsb, dqsosc, delay_us;
|
||||
unsigned int c, d, idx;
|
||||
unsigned long clocks;
|
||||
|
||||
clocks = tegra210_emc_actual_osc_clocks(curr->run_clocks);
|
||||
delay_us = 2 + (clocks / rate_mhz);
|
||||
|
||||
tegra210_emc_start_periodic_compensation(emc);
|
||||
udelay(delay_us);
|
||||
|
||||
for (d = 0; d < emc->num_devices; d++) {
|
||||
/* Read DQSOSC from MRR18/19 */
|
||||
msb = tegra210_emc_mrr_read(emc, 2 - d, 19);
|
||||
lsb = tegra210_emc_mrr_read(emc, 2 - d, 18);
|
||||
|
||||
for (c = 0; c < emc->num_channels; c++) {
|
||||
/* C[c]D[d]U[0] */
|
||||
idx = c * 4 + d * 2;
|
||||
|
||||
dqsosc = (msb & 0x00ff) << 8;
|
||||
dqsosc |= (lsb & 0x00ff) >> 0;
|
||||
|
||||
/* Check for unpopulated channels */
|
||||
if (dqsosc)
|
||||
delay[idx] = (clocks * 1000000) /
|
||||
(rate_mhz * 2 * dqsosc);
|
||||
|
||||
/* C[c]D[d]U[1] */
|
||||
idx++;
|
||||
|
||||
dqsosc = (msb & 0xff00) << 0;
|
||||
dqsosc |= (lsb & 0xff00) >> 8;
|
||||
|
||||
/* Check for unpopulated channels */
|
||||
if (dqsosc)
|
||||
delay[idx] = (clocks * 1000000) /
|
||||
(rate_mhz * 2 * dqsosc);
|
||||
|
||||
msb >>= 16;
|
||||
lsb >>= 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
|
||||
struct tegra210_emc_timing *last,
|
||||
struct tegra210_emc_timing *next)
|
||||
{
|
||||
#define __COPY_EMA(nt, lt, dev) \
|
||||
({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \
|
||||
(nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
|
||||
|
||||
u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX];
|
||||
u32 delay;
|
||||
|
||||
delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
delay *= 1000;
|
||||
delay = 2 + (delay / last->rate);
|
||||
u32 i, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX];
|
||||
u32 delay[DRAM_CLKTREE_NUM], idx;
|
||||
bool over = false;
|
||||
|
||||
if (!next->periodic_training)
|
||||
return 0;
|
||||
|
@ -427,57 +203,46 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
|
|||
* calibration then we can reuse the previous
|
||||
* frequencies EMA data.
|
||||
*/
|
||||
__COPY_EMA(next, last, C0D0U0);
|
||||
__COPY_EMA(next, last, C0D0U1);
|
||||
__COPY_EMA(next, last, C1D0U0);
|
||||
__COPY_EMA(next, last, C1D0U1);
|
||||
__COPY_EMA(next, last, C0D1U0);
|
||||
__COPY_EMA(next, last, C0D1U1);
|
||||
__COPY_EMA(next, last, C1D1U0);
|
||||
__COPY_EMA(next, last, C1D1U1);
|
||||
for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
|
||||
__COPY_EMA(next, last, idx);
|
||||
} else {
|
||||
/* Reset the EMA.*/
|
||||
__MOVAVG(next, C0D0U0) = 0;
|
||||
__MOVAVG(next, C0D0U1) = 0;
|
||||
__MOVAVG(next, C1D0U0) = 0;
|
||||
__MOVAVG(next, C1D0U1) = 0;
|
||||
__MOVAVG(next, C0D1U0) = 0;
|
||||
__MOVAVG(next, C0D1U1) = 0;
|
||||
__MOVAVG(next, C1D1U0) = 0;
|
||||
__MOVAVG(next, C1D1U1) = 0;
|
||||
for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
|
||||
__MOVAVG(next, idx) = 0;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
tegra210_emc_start_periodic_compensation(emc);
|
||||
udelay(delay);
|
||||
/* Generate next sample of data. */
|
||||
tegra210_emc_get_clktree_delay(emc, delay);
|
||||
|
||||
/*
|
||||
* Generate next sample of data.
|
||||
*/
|
||||
adel = update_clock_tree_delay(emc, DVFS_PT1);
|
||||
for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
|
||||
__INCREMENT_PTFV(idx, delay[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Seems like it should be part of the
|
||||
* 'if (last_timing->periodic_training)' conditional
|
||||
* since is already done for the else clause.
|
||||
*/
|
||||
adel = update_clock_tree_delay(emc, DVFS_UPDATE);
|
||||
for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) {
|
||||
/* Do the division part of the moving average */
|
||||
__AVERAGE_PTFV(idx);
|
||||
over |= tegra210_emc_compare_update_delay(next,
|
||||
__MOVAVG_AC(next, idx), idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == PERIODIC_TRAINING_SEQUENCE) {
|
||||
tegra210_emc_start_periodic_compensation(emc);
|
||||
udelay(delay);
|
||||
tegra210_emc_get_clktree_delay(emc, delay);
|
||||
|
||||
adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE);
|
||||
for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) {
|
||||
__WEIGHTED_UPDATE_PTFV(idx, delay[idx]);
|
||||
over |= tegra210_emc_compare_update_delay(next,
|
||||
__MOVAVG_AC(next, idx), idx);
|
||||
}
|
||||
}
|
||||
|
||||
return adel;
|
||||
return over;
|
||||
}
|
||||
|
||||
static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
|
||||
{
|
||||
u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value;
|
||||
u32 emc_cfg, emc_cfg_o, emc_cfg_update, value;
|
||||
static const u32 list[] = {
|
||||
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,
|
||||
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,
|
||||
|
@ -492,7 +257,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
|
|||
};
|
||||
struct tegra210_emc_timing *last = emc->last;
|
||||
unsigned int items = ARRAY_SIZE(list), i;
|
||||
unsigned long delay;
|
||||
|
||||
if (last->periodic_training) {
|
||||
emc_dbg(emc, PER_TRAIN, "Periodic training starting\n");
|
||||
|
@ -530,30 +294,18 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
|
|||
/*
|
||||
* 2. osc kick off - this assumes training and dvfs have set
|
||||
* correct MR23.
|
||||
*/
|
||||
tegra210_emc_start_periodic_compensation(emc);
|
||||
|
||||
/*
|
||||
*
|
||||
* 3. Let dram capture its clock tree delays.
|
||||
*/
|
||||
delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
delay *= 1000;
|
||||
delay /= last->rate + 1;
|
||||
udelay(delay);
|
||||
|
||||
/*
|
||||
*
|
||||
* 4. Check delta wrt previous values (save value if margin
|
||||
* exceeds what is set in table).
|
||||
*/
|
||||
del = periodic_compensation_handler(emc,
|
||||
PERIODIC_TRAINING_SEQUENCE,
|
||||
last, last);
|
||||
|
||||
if (periodic_compensation_handler(emc, PERIODIC_TRAINING_SEQUENCE,
|
||||
last, last)) {
|
||||
/*
|
||||
* 5. Apply compensation w.r.t. trained values (if clock tree
|
||||
* has drifted more than the set margin).
|
||||
*/
|
||||
if (last->tree_margin < ((del * 128 * (last->rate / 1000)) / 1000000)) {
|
||||
for (i = 0; i < items; i++) {
|
||||
value = tegra210_emc_compensate(last, list[i]);
|
||||
emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n",
|
||||
|
@ -734,16 +486,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
|
|||
EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK,
|
||||
0);
|
||||
|
||||
tegra210_emc_start_periodic_compensation(emc);
|
||||
|
||||
delay = 1000 * tegra210_emc_actual_osc_clocks(last->run_clocks);
|
||||
udelay((delay / last->rate) + 2);
|
||||
|
||||
value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake,
|
||||
next);
|
||||
value = (value * 128 * next->rate / 1000) / 1000000;
|
||||
|
||||
if (next->periodic_training && value > next->tree_margin)
|
||||
if (periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, next))
|
||||
compensate_trimmer_applicable = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -979,7 +979,6 @@ static int emc_check_mc_timings(struct tegra_emc *emc)
|
|||
static int emc_load_timings_from_dt(struct tegra_emc *emc,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct emc_timing *timing;
|
||||
int child_count;
|
||||
int err;
|
||||
|
@ -998,12 +997,10 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
emc->num_timings = child_count;
|
||||
timing = emc->timings;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
for_each_child_of_node_scoped(node, child) {
|
||||
err = load_one_timing_from_dt(emc, timing++, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/ti-aemif.h>
|
||||
|
||||
#define TA_SHIFT 2
|
||||
#define RHOLD_SHIFT 4
|
||||
|
@ -330,42 +329,27 @@ static int aemif_probe(struct platform_device *pdev)
|
|||
int ret = -ENODEV;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *child_np;
|
||||
struct aemif_device *aemif;
|
||||
struct aemif_platform_data *pdata;
|
||||
struct of_dev_auxdata *dev_lookup;
|
||||
|
||||
aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
|
||||
if (!aemif)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
dev_lookup = pdata ? pdata->dev_lookup : NULL;
|
||||
|
||||
platform_set_drvdata(pdev, aemif);
|
||||
|
||||
aemif->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(aemif->clk)) {
|
||||
dev_err(dev, "cannot get clock 'aemif'\n");
|
||||
return PTR_ERR(aemif->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(aemif->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
aemif->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(aemif->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(aemif->clk),
|
||||
"cannot get clock 'aemif'\n");
|
||||
|
||||
aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
|
||||
|
||||
if (np && of_device_is_compatible(np, "ti,da850-aemif"))
|
||||
aemif->cs_offset = 2;
|
||||
else if (pdata)
|
||||
aemif->cs_offset = pdata->cs_offset;
|
||||
|
||||
aemif->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(aemif->base)) {
|
||||
ret = PTR_ERR(aemif->base);
|
||||
goto error;
|
||||
}
|
||||
if (IS_ERR(aemif->base))
|
||||
return PTR_ERR(aemif->base);
|
||||
|
||||
if (np) {
|
||||
/*
|
||||
|
@ -374,17 +358,10 @@ static int aemif_probe(struct platform_device *pdev)
|
|||
* functions iterate over these nodes and update the cs data
|
||||
* array.
|
||||
*/
|
||||
for_each_available_child_of_node(np, child_np) {
|
||||
for_each_available_child_of_node_scoped(np, child_np) {
|
||||
ret = of_aemif_parse_abus_config(pdev, child_np);
|
||||
if (ret < 0) {
|
||||
of_node_put(child_np);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else if (pdata && pdata->num_abus_data > 0) {
|
||||
for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) {
|
||||
aemif->cs_data[i].cs = pdata->abus_data[i].cs;
|
||||
aemif_get_hw_params(pdev, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +370,7 @@ static int aemif_probe(struct platform_device *pdev)
|
|||
if (ret < 0) {
|
||||
dev_err(dev, "Error configuring chip select %d\n",
|
||||
aemif->cs_data[i].cs);
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,41 +379,18 @@ static int aemif_probe(struct platform_device *pdev)
|
|||
* child will be probed after the AEMIF timing parameters are set.
|
||||
*/
|
||||
if (np) {
|
||||
for_each_available_child_of_node(np, child_np) {
|
||||
ret = of_platform_populate(child_np, NULL,
|
||||
dev_lookup, dev);
|
||||
if (ret < 0) {
|
||||
of_node_put(child_np);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else if (pdata) {
|
||||
for (i = 0; i < pdata->num_sub_devices; i++) {
|
||||
pdata->sub_devices[i].dev.parent = dev;
|
||||
ret = platform_device_register(&pdata->sub_devices[i]);
|
||||
if (ret) {
|
||||
dev_warn(dev, "Error register sub device %s\n",
|
||||
pdata->sub_devices[i].name);
|
||||
}
|
||||
for_each_available_child_of_node_scoped(np, child_np) {
|
||||
ret = of_platform_populate(child_np, NULL, NULL, dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
clk_disable_unprepare(aemif->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aemif_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(aemif->clk);
|
||||
}
|
||||
|
||||
static struct platform_driver aemif_driver = {
|
||||
.probe = aemif_probe,
|
||||
.remove_new = aemif_remove,
|
||||
.driver = {
|
||||
.name = "ti-aemif",
|
||||
.of_match_table = of_match_ptr(aemif_of_match),
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* TI DaVinci AEMIF platform glue.
|
||||
*
|
||||
* Copyright (C) 2017 BayLibre SAS
|
||||
*
|
||||
* Author:
|
||||
* Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __TI_DAVINCI_AEMIF_DATA_H__
|
||||
#define __TI_DAVINCI_AEMIF_DATA_H__
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/**
|
||||
* struct aemif_abus_data - Async bus configuration parameters.
|
||||
*
|
||||
* @cs - Chip-select number.
|
||||
*/
|
||||
struct aemif_abus_data {
|
||||
u32 cs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct aemif_platform_data - Data to set up the TI aemif driver.
|
||||
*
|
||||
* @dev_lookup: of_dev_auxdata passed to of_platform_populate() for aemif
|
||||
* subdevices.
|
||||
* @cs_offset: Lowest allowed chip-select number.
|
||||
* @abus_data: Array of async bus configuration entries.
|
||||
* @num_abus_data: Number of abus entries.
|
||||
* @sub_devices: Array of platform subdevices.
|
||||
* @num_sub_devices: Number of subdevices.
|
||||
*/
|
||||
struct aemif_platform_data {
|
||||
struct of_dev_auxdata *dev_lookup;
|
||||
u32 cs_offset;
|
||||
struct aemif_abus_data *abus_data;
|
||||
size_t num_abus_data;
|
||||
struct platform_device *sub_devices;
|
||||
size_t num_sub_devices;
|
||||
};
|
||||
|
||||
#endif /* __TI_DAVINCI_AEMIF_DATA_H__ */
|
Loading…
Reference in a new issue