diff options
Diffstat (limited to 'drivers/memory')
-rw-r--r-- | drivers/memory/Kconfig | 11 | ||||
-rw-r--r-- | drivers/memory/Makefile | 1 | ||||
-rw-r--r-- | drivers/memory/atmel-ebi.c | 766 | ||||
-rw-r--r-- | drivers/memory/atmel-sdramc.c | 11 | ||||
-rw-r--r-- | drivers/memory/mtk-smi.c | 167 | ||||
-rw-r--r-- | drivers/memory/omap-gpmc.c | 141 | ||||
-rw-r--r-- | drivers/memory/samsung/exynos-srom.c | 41 | ||||
-rw-r--r-- | drivers/memory/tegra/mc.c | 10 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra124-emc.c | 8 |
9 files changed, 1018 insertions, 138 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 5645705c7110..4b4c0c3c3d2f 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -25,6 +25,17 @@ config ATMEL_SDRAMC Starting with the at91sam9g45, this controller supports SDR, DDR and LP-DDR memories. +config ATMEL_EBI + bool "Atmel EBI driver" + default y + depends on ARCH_AT91 && OF + select MFD_SYSCON + help + Driver for Atmel EBI controller. + Used to configure the EBI (external bus interface) when the device- + tree is used. This bus supports NANDs, external ethernet controller, + SRAMs, ATA devices, etc. + config TI_AEMIF tristate "Texas Instruments AEMIF driver" depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index cb0b7a1df11a..b20ae38b5bfb 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_OF) += of_memory.o endif obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o +obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_EMIF) += emif.o obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c new file mode 100644 index 000000000000..f87ad6f5d2dc --- /dev/null +++ b/drivers/memory/atmel-ebi.c @@ -0,0 +1,766 @@ +/* + * EBI driver for Atmel chips + * inspired by the fsl weim bus driver + * + * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/atmel-matrix.h> +#include <linux/mfd/syscon/atmel-smc.h> +#include <linux/init.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +struct at91sam9_smc_timings { + u32 ncs_rd_setup_ns; + u32 nrd_setup_ns; + u32 ncs_wr_setup_ns; + u32 nwe_setup_ns; + u32 ncs_rd_pulse_ns; + u32 nrd_pulse_ns; + u32 ncs_wr_pulse_ns; + u32 nwe_pulse_ns; + u32 nrd_cycle_ns; + u32 nwe_cycle_ns; + u32 tdf_ns; +}; + +struct at91sam9_smc_generic_fields { + struct regmap_field *setup; + struct regmap_field *pulse; + struct regmap_field *cycle; + struct regmap_field *mode; +}; + +struct at91sam9_ebi_dev_config { + struct at91sam9_smc_timings timings; + u32 mode; +}; + +struct at91_ebi_dev_config { + int cs; + union { + struct at91sam9_ebi_dev_config sam9; + }; +}; + +struct at91_ebi; + +struct at91_ebi_dev { + struct list_head node; + struct at91_ebi *ebi; + u32 mode; + int numcs; + struct at91_ebi_dev_config configs[]; +}; + +struct at91_ebi_caps { + unsigned int available_cs; + const struct reg_field *ebi_csa; + void (*get_config)(struct at91_ebi_dev *ebid, + struct at91_ebi_dev_config *conf); + int (*xlate_config)(struct at91_ebi_dev *ebid, + struct device_node *configs_np, + struct at91_ebi_dev_config *conf); + int (*apply_config)(struct at91_ebi_dev *ebid, + struct at91_ebi_dev_config *conf); + int (*init)(struct at91_ebi *ebi); +}; + +struct at91_ebi { + struct clk *clk; + struct regmap *smc; + struct regmap *matrix; + + struct regmap_field *ebi_csa; + + struct device *dev; + const struct at91_ebi_caps *caps; + struct list_head devs; + union { + struct at91sam9_smc_generic_fields sam9; + }; +}; + +static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid, + struct at91_ebi_dev_config *conf) +{ + struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9; + unsigned int clk_rate = clk_get_rate(ebid->ebi->clk); + struct at91sam9_ebi_dev_config *config = &conf->sam9; + struct at91sam9_smc_timings *timings = &config->timings; + unsigned int val; + + regmap_fields_read(fields->mode, conf->cs, &val); + config->mode = val & ~AT91_SMC_TDF; + + val = (val & AT91_SMC_TDF) >> 16; + timings->tdf_ns = clk_rate * val; + + regmap_fields_read(fields->setup, conf->cs, &val); + timings->ncs_rd_setup_ns = (val >> 24) & 0x1f; + timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128; + timings->ncs_rd_setup_ns *= clk_rate; + timings->nrd_setup_ns = (val >> 16) & 0x1f; + timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128; + timings->nrd_setup_ns *= clk_rate; + timings->ncs_wr_setup_ns = (val >> 8) & 0x1f; + timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128; + timings->ncs_wr_setup_ns *= clk_rate; + timings->nwe_setup_ns = val & 0x1f; + timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128; + timings->nwe_setup_ns *= clk_rate; + + regmap_fields_read(fields->pulse, conf->cs, &val); + timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f; + timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256; + timings->ncs_rd_pulse_ns *= clk_rate; + timings->nrd_pulse_ns = (val >> 16) & 0x3f; + timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256; + timings->nrd_pulse_ns *= clk_rate; + timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f; + timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256; + timings->ncs_wr_pulse_ns *= clk_rate; + timings->nwe_pulse_ns = val & 0x3f; + timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256; + timings->nwe_pulse_ns *= clk_rate; + + regmap_fields_read(fields->cycle, conf->cs, &val); + timings->nrd_cycle_ns = (val >> 16) & 0x7f; + timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256; + timings->nrd_cycle_ns *= clk_rate; + timings->nwe_cycle_ns = val & 0x7f; + timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256; + timings->nwe_cycle_ns *= clk_rate; +} + +static int at91_xlate_timing(struct device_node *np, const char *prop, + u32 *val, bool *required) +{ + if (!of_property_read_u32(np, prop, val)) { + *required = true; + return 0; + } + + if (*required) + return -EINVAL; + + return 0; +} + +static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid, + struct device_node *np, + struct at91sam9_smc_timings *timings, + bool *required) +{ + int ret; + + ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns", + &timings->ncs_rd_setup_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns", + &timings->nrd_setup_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns", + &timings->ncs_wr_setup_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns", + &timings->nwe_setup_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns", + &timings->ncs_rd_pulse_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns", + &timings->nrd_pulse_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns", + &timings->ncs_wr_pulse_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns", + &timings->nwe_pulse_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns", + &timings->nwe_cycle_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns", + &timings->nrd_cycle_ns, required); + if (ret) + goto out; + + ret = at91_xlate_timing(np, "atmel,smc-tdf-ns", + &timings->tdf_ns, required); + +out: + if (ret) + dev_err(ebid->ebi->dev, + "missing or invalid timings definition in %s", + np->full_name); + + return ret; +} + +static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, + struct device_node *np, + struct at91_ebi_dev_config *conf) +{ + struct at91sam9_ebi_dev_config *config = &conf->sam9; + bool required = false; + const char *tmp_str; + u32 tmp; + int ret; + + ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp); + if (!ret) { + switch (tmp) { + case 8: + config->mode |= AT91_SMC_DBW_8; + break; + + case 16: + config->mode |= AT91_SMC_DBW_16; + break; + + case 32: + config->mode |= AT91_SMC_DBW_32; + break; + + default: + return -EINVAL; + } + + required = true; + } + + if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) { + config->mode |= AT91_SMC_TDFMODE_OPTIMIZED; + required = true; + } + + tmp_str = NULL; + of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str); + if (tmp_str && !strcmp(tmp_str, "write")) { + config->mode |= AT91_SMC_BAT_WRITE; + required = true; + } + + tmp_str = NULL; + of_property_read_string(np, "atmel,smc-read-mode", &tmp_str); + if (tmp_str && !strcmp(tmp_str, "nrd")) { + config->mode |= AT91_SMC_READMODE_NRD; + required = true; + } + + tmp_str = NULL; + of_property_read_string(np, "atmel,smc-write-mode", &tmp_str); + if (tmp_str && !strcmp(tmp_str, "nwe")) { + config->mode |= AT91_SMC_WRITEMODE_NWE; + required = true; + } + + tmp_str = NULL; + of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str); + if (tmp_str) { + if (!strcmp(tmp_str, "frozen")) + config->mode |= AT91_SMC_EXNWMODE_FROZEN; + else if (!strcmp(tmp_str, "ready")) + config->mode |= AT91_SMC_EXNWMODE_READY; + else if (strcmp(tmp_str, "disabled")) + return -EINVAL; + + required = true; + } + + ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp); + if (!ret) { + switch (tmp) { + case 4: + config->mode |= AT91_SMC_PS_4; + break; + + case 8: + config->mode |= AT91_SMC_PS_8; + break; + + case 16: + config->mode |= AT91_SMC_PS_16; + break; + + case 32: + config->mode |= AT91_SMC_PS_32; + break; + + default: + return -EINVAL; + } + + config->mode |= AT91_SMC_PMEN; + required = true; + } + + ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings, + &required); + if (ret) + return ret; + + return required; +} + +static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid, + struct at91_ebi_dev_config *conf) +{ + unsigned int clk_rate = clk_get_rate(ebid->ebi->clk); + struct at91sam9_ebi_dev_config *config = &conf->sam9; + struct at91sam9_smc_timings *timings = &config->timings; + struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9; + u32 coded_val; + u32 val; + + coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, + timings->ncs_rd_setup_ns); + val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val); + coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, + timings->nrd_setup_ns); + val |= AT91SAM9_SMC_NRDSETUP(coded_val); + coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, + timings->ncs_wr_setup_ns); + val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val); + coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, + timings->nwe_setup_ns); + val |= AT91SAM9_SMC_NWESETUP(coded_val); + regmap_fields_write(fields->setup, conf->cs, val); + + coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, + timings->ncs_rd_pulse_ns); + val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val); + coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, + timings->nrd_pulse_ns); + val |= AT91SAM9_SMC_NRDPULSE(coded_val); + coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, + timings->ncs_wr_pulse_ns); + val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val); + coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, + timings->nwe_pulse_ns); + val |= AT91SAM9_SMC_NWEPULSE(coded_val); + regmap_fields_write(fields->pulse, conf->cs, val); + + coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate, + timings->nrd_cycle_ns); + val = AT91SAM9_SMC_NRDCYCLE(coded_val); + coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate, + timings->nwe_cycle_ns); + val |= AT91SAM9_SMC_NWECYCLE(coded_val); + regmap_fields_write(fields->cycle, conf->cs, val); + + val = DIV_ROUND_UP(timings->tdf_ns, clk_rate); + if (val > AT91_SMC_TDF_MAX) + val = AT91_SMC_TDF_MAX; + regmap_fields_write(fields->mode, conf->cs, + config->mode | AT91_SMC_TDF_(val)); + + return 0; +} + +static int at91sam9_ebi_init(struct at91_ebi *ebi) +{ + struct at91sam9_smc_generic_fields *fields = &ebi->sam9; + struct reg_field field = REG_FIELD(0, 0, 31); + + field.id_size = fls(ebi->caps->available_cs); + field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ; + + field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC); + fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->setup)) + return PTR_ERR(fields->setup); + + field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC); + fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->pulse)) + return PTR_ERR(fields->pulse); + + field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC); + fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->cycle)) + return PTR_ERR(fields->cycle); + + field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC); + fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->mode)) + return PTR_ERR(fields->mode); + + return 0; +} + +static int sama5d3_ebi_init(struct at91_ebi *ebi) +{ + struct at91sam9_smc_generic_fields *fields = &ebi->sam9; + struct reg_field field = REG_FIELD(0, 0, 31); + + field.id_size = fls(ebi->caps->available_cs); + field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ; + + field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC); + fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->setup)) + return PTR_ERR(fields->setup); + + field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC); + fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->pulse)) + return PTR_ERR(fields->pulse); + + field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC); + fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->cycle)) + return PTR_ERR(fields->cycle); + + field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC); + fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field); + if (IS_ERR(fields->mode)) + return PTR_ERR(fields->mode); + + return 0; +} + +static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, + int reg_cells) +{ + const struct at91_ebi_caps *caps = ebi->caps; + struct at91_ebi_dev_config conf = { }; + struct device *dev = ebi->dev; + struct at91_ebi_dev *ebid; + int ret, numcs = 0, i; + bool apply = false; + + numcs = of_property_count_elems_of_size(np, "reg", + reg_cells * sizeof(u32)); + if (numcs <= 0) { + dev_err(dev, "invalid reg property in %s\n", np->full_name); + return -EINVAL; + } + + ebid = devm_kzalloc(ebi->dev, + sizeof(*ebid) + (numcs * sizeof(*ebid->configs)), + GFP_KERNEL); + if (!ebid) + return -ENOMEM; + + ebid->ebi = ebi; + + ret = caps->xlate_config(ebid, np, &conf); + if (ret < 0) + return ret; + else if (ret) + apply = true; + + for (i = 0; i < numcs; i++) { + u32 cs; + + ret = of_property_read_u32_index(np, "reg", i * reg_cells, + &cs); + if (ret) + return ret; + + if (cs > AT91_MATRIX_EBI_NUM_CS || + !(ebi->caps->available_cs & BIT(cs))) { + dev_err(dev, "invalid reg property in %s\n", + np->full_name); + return -EINVAL; + } + + ebid->configs[i].cs = cs; + + if (apply) { + conf.cs = cs; + ret = caps->apply_config(ebid, &conf); + if (ret) + return ret; + } + + caps->get_config(ebid, &ebid->configs[i]); + + /* + * Attach the EBI device to the generic SMC logic if at least + * one "atmel,smc-" property is present. + */ + if (ebi->ebi_csa && ret) + regmap_field_update_bits(ebi->ebi_csa, + BIT(cs), 0); + } + + list_add_tail(&ebid->node, &ebi->devs); + + return 0; +} + +static const struct reg_field at91sam9260_ebi_csa = + REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9260_ebi_caps = { + .available_cs = 0xff, + .ebi_csa = &at91sam9260_ebi_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct reg_field at91sam9261_ebi_csa = + REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9261_ebi_caps = { + .available_cs = 0xff, + .ebi_csa = &at91sam9261_ebi_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct reg_field at91sam9263_ebi0_csa = + REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9263_ebi0_caps = { + .available_cs = 0x3f, + .ebi_csa = &at91sam9263_ebi0_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct reg_field at91sam9263_ebi1_csa = + REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9263_ebi1_caps = { + .available_cs = 0x7, + .ebi_csa = &at91sam9263_ebi1_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct reg_field at91sam9rl_ebi_csa = + REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9rl_ebi_caps = { + .available_cs = 0x3f, + .ebi_csa = &at91sam9rl_ebi_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct reg_field at91sam9g45_ebi_csa = + REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0, + AT91_MATRIX_EBI_NUM_CS - 1); + +static const struct at91_ebi_caps at91sam9g45_ebi_caps = { + .available_cs = 0x3f, + .ebi_csa = &at91sam9g45_ebi_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct at91_ebi_caps at91sam9x5_ebi_caps = { + .available_cs = 0x3f, + .ebi_csa = &at91sam9263_ebi0_csa, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = at91sam9_ebi_init, +}; + +static const struct at91_ebi_caps sama5d3_ebi_caps = { + .available_cs = 0xf, + .get_config = at91sam9_ebi_get_config, + .xlate_config = at91sam9_ebi_xslate_config, + .apply_config = at91sam9_ebi_apply_config, + .init = sama5d3_ebi_init, +}; + +static const struct of_device_id at91_ebi_id_table[] = { + { + .compatible = "atmel,at91sam9260-ebi", + .data = &at91sam9260_ebi_caps, + }, + { + .compatible = "atmel,at91sam9261-ebi", + .data = &at91sam9261_ebi_caps, + }, + { + .compatible = "atmel,at91sam9263-ebi0", + .data = &at91sam9263_ebi0_caps, + }, + { + .compatible = "atmel,at91sam9263-ebi1", + .data = &at91sam9263_ebi1_caps, + }, + { + .compatible = "atmel,at91sam9rl-ebi", + .data = &at91sam9rl_ebi_caps, + }, + { + .compatible = "atmel,at91sam9g45-ebi", + .data = &at91sam9g45_ebi_caps, + }, + { + .compatible = "atmel,at91sam9x5-ebi", + .data = &at91sam9x5_ebi_caps, + }, + { + .compatible = "atmel,sama5d3-ebi", + .data = &sama5d3_ebi_caps, + }, + { /* sentinel */ } +}; + +static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np) +{ + struct device *dev = ebi->dev; + struct property *newprop; + + newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL); + if (!newprop) + return -ENOMEM; + + newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL); + if (!newprop->name) + return -ENOMEM; + + newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL); + if (!newprop->name) + return -ENOMEM; + + newprop->length = sizeof("disabled"); + + return of_update_property(np, newprop); +} + +static int at91_ebi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *child, *np = dev->of_node; + const struct of_device_id *match; + struct at91_ebi *ebi; + int ret, reg_cells; + struct clk *clk; + u32 val; + + match = of_match_device(at91_ebi_id_table, dev); + if (!match || !match->data) + return -EINVAL; + + ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL); + if (!ebi) + return -ENOMEM; + + INIT_LIST_HEAD(&ebi->devs); + ebi->caps = match->data; + ebi->dev = dev; + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ebi->clk = clk; + + ebi->smc = syscon_regmap_lookup_by_phandle(np, "atmel,smc"); + if (IS_ERR(ebi->smc)) + return PTR_ERR(ebi->smc); + + /* + * The sama5d3 does not provide an EBICSA register and thus does need + * to access the matrix registers. + */ + if (ebi->caps->ebi_csa) { + ebi->matrix = + syscon_regmap_lookup_by_phandle(np, "atmel,matrix"); + if (IS_ERR(ebi->matrix)) + return PTR_ERR(ebi->matrix); + + ebi->ebi_csa = regmap_field_alloc(ebi->matrix, + *ebi->caps->ebi_csa); + if (IS_ERR(ebi->ebi_csa)) + return PTR_ERR(ebi->ebi_csa); + } + + ret = ebi->caps->init(ebi); + if (ret) + return ret; + + ret = of_property_read_u32(np, "#address-cells", &val); + if (ret) { + dev_err(dev, "missing #address-cells property\n"); + return ret; + } + + reg_cells = val; + + ret = of_property_read_u32(np, "#size-cells", &val); + if (ret) { + dev_err(dev, "missing #address-cells property\n"); + return ret; + } + + reg_cells += val; + + for_each_available_child_of_node(np, child) { + if (!of_find_property(child, "reg", NULL)) + continue; + + ret = at91_ebi_dev_setup(ebi, child, reg_cells); + if (ret) { + dev_err(dev, "failed to configure EBI bus for %s, disabling the device", + child->full_name); + + ret = at91_ebi_dev_disable(ebi, child); + if (ret) + return ret; + } + } + + return of_platform_populate(np, NULL, NULL, dev); +} + +static struct platform_driver at91_ebi_driver = { + .driver = { + .name = "atmel-ebi", + .of_match_table = at91_ebi_id_table, + }, +}; +builtin_platform_driver_probe(at91_ebi_driver, at91_ebi_probe); diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c index a3ebc8a87479..53a341f3b305 100644 --- a/drivers/memory/atmel-sdramc.c +++ b/drivers/memory/atmel-sdramc.c @@ -1,6 +1,8 @@ /* * Atmel (Multi-port DDR-)SDRAM Controller driver * + * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com> + * * Copyright (C) 2014 Atmel * * This program is free software: you can redistribute it and/or modify @@ -20,7 +22,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -48,7 +50,6 @@ static const struct of_device_id atmel_ramc_of_match[] = { { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, }, {}, }; -MODULE_DEVICE_TABLE(of, atmel_ramc_of_match); static int atmel_ramc_probe(struct platform_device *pdev) { @@ -90,8 +91,4 @@ static int __init atmel_ramc_init(void) { return platform_driver_register(&atmel_ramc_driver); } -module_init(atmel_ramc_init); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); -MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller"); +device_initcall(atmel_ramc_init); diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index f6b57579185a..4afbc412f959 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -21,19 +21,50 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <soc/mediatek/smi.h> +#include <dt-bindings/memory/mt2701-larb-port.h> #define SMI_LARB_MMU_EN 0xf00 +#define REG_SMI_SECUR_CON_BASE 0x5c0 + +/* every register control 8 port, register offset 0x4 */ +#define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2) +#define REG_SMI_SECUR_CON_ADDR(id) \ + (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id)) + +/* + * every port have 4 bit to control, bit[port + 3] control virtual or physical, + * bit[port + 2 : port + 1] control the domain, bit[port] control the security + * or non-security. + */ +#define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2))) +#define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3) +/* mt2701 domain should be set to 3 */ +#define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1)) + +struct mtk_smi_larb_gen { + int port_in_larb[MTK_LARB_NR_MAX + 1]; + void (*config_port)(struct device *); +}; struct mtk_smi { - struct device *dev; - struct clk *clk_apb, *clk_smi; + struct device *dev; + struct clk *clk_apb, *clk_smi; + struct clk *clk_async; /*only needed by mt2701*/ + void __iomem *smi_ao_base; }; struct mtk_smi_larb { /* larb: local arbiter */ - struct mtk_smi smi; - void __iomem *base; - struct device *smi_common_dev; - u32 *mmu; + struct mtk_smi smi; + void __iomem *base; + struct device *smi_common_dev; + const struct mtk_smi_larb_gen *larb_gen; + int larbid; + u32 *mmu; +}; + +enum mtk_smi_gen { + MTK_SMI_GEN1, + MTK_SMI_GEN2 }; static int mtk_smi_enable(const struct mtk_smi *smi) @@ -71,6 +102,7 @@ static void mtk_smi_disable(const struct mtk_smi *smi) int mtk_smi_larb_get(struct device *larbdev) { struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); + const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); int ret; @@ -87,7 +119,7 @@ int mtk_smi_larb_get(struct device *larbdev) } /* Configure the iommu info for this larb */ - writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); + larb_gen->config_port(larbdev); return 0; } @@ -126,6 +158,45 @@ mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) return -ENODEV; } +static void mtk_smi_larb_config_port(struct device *dev) +{ + struct mtk_smi_larb *larb = dev_get_drvdata(dev); + + writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); +} + + +static void mtk_smi_larb_config_port_gen1(struct device *dev) +{ + struct mtk_smi_larb *larb = dev_get_drvdata(dev); + const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; + struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); + int i, m4u_port_id, larb_port_num; + u32 sec_con_val, reg_val; + + m4u_port_id = larb_gen->port_in_larb[larb->larbid]; + larb_port_num = larb_gen->port_in_larb[larb->larbid + 1] + - larb_gen->port_in_larb[larb->larbid]; + + for (i = 0; i < larb_port_num; i++, m4u_port_id++) { + if (*larb->mmu & BIT(i)) { + /* bit[port + 3] controls the virtual or physical */ + sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id); + } else { + /* do not need to enable m4u for this port */ + continue; + } + reg_val = readl(common->smi_ao_base + + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); + reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id); + reg_val |= sec_con_val; + reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id); + writel(reg_val, + common->smi_ao_base + + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); + } +} + static void mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) { @@ -137,6 +208,31 @@ static const struct component_ops mtk_smi_larb_component_ops = { .unbind = mtk_smi_larb_unbind, }; +static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { + /* mt8173 do not need the port in larb */ + .config_port = mtk_smi_larb_config_port, +}; + +static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { + .port_in_larb = { + LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, + LARB2_PORT_OFFSET, LARB3_PORT_OFFSET + }, + .config_port = mtk_smi_larb_config_port_gen1, +}; + +static const struct of_device_id mtk_smi_larb_of_ids[] = { + { + .compatible = "mediatek,mt8173-smi-larb", + .data = &mtk_smi_larb_mt8173 + }, + { + .compatible = "mediatek,mt2701-smi-larb", + .data = &mtk_smi_larb_mt2701 + }, + {} +}; + static int mtk_smi_larb_probe(struct platform_device *pdev) { struct mtk_smi_larb *larb; @@ -144,14 +240,20 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *smi_node; struct platform_device *smi_pdev; + const struct of_device_id *of_id; if (!dev->pm_domain) return -EPROBE_DEFER; + of_id = of_match_node(mtk_smi_larb_of_ids, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); if (!larb) return -ENOMEM; + larb->larb_gen = of_id->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); larb->base = devm_ioremap_resource(dev, res); if (IS_ERR(larb->base)) @@ -191,24 +293,34 @@ static int mtk_smi_larb_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id mtk_smi_larb_of_ids[] = { - { .compatible = "mediatek,mt8173-smi-larb",}, - {} -}; - static struct platform_driver mtk_smi_larb_driver = { .probe = mtk_smi_larb_probe, - .remove = mtk_smi_larb_remove, + .remove = mtk_smi_larb_remove, .driver = { .name = "mtk-smi-larb", .of_match_table = mtk_smi_larb_of_ids, } }; +static const struct of_device_id mtk_smi_common_of_ids[] = { + { + .compatible = "mediatek,mt8173-smi-common", + .data = (void *)MTK_SMI_GEN2 + }, + { + .compatible = "mediatek,mt2701-smi-common", + .data = (void *)MTK_SMI_GEN1 + }, + {} +}; + static int mtk_smi_common_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_smi *common; + struct resource *res; + const struct of_device_id *of_id; + enum mtk_smi_gen smi_gen; if (!dev->pm_domain) return -EPROBE_DEFER; @@ -226,6 +338,29 @@ static int mtk_smi_common_probe(struct platform_device *pdev) if (IS_ERR(common->clk_smi)) return PTR_ERR(common->clk_smi); + of_id = of_match_node(mtk_smi_common_of_ids, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + + /* + * for mtk smi gen 1, we need to get the ao(always on) base to config + * m4u port, and we need to enable the aync clock for transform the smi + * clock into emi clock domain, but for mtk smi gen2, there's no smi ao + * base. + */ + smi_gen = (enum mtk_smi_gen)of_id->data; + if (smi_gen == MTK_SMI_GEN1) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + common->smi_ao_base = devm_ioremap_resource(dev, res); + if (IS_ERR(common->smi_ao_base)) + return PTR_ERR(common->smi_ao_base); + + common->clk_async = devm_clk_get(dev, "async"); + if (IS_ERR(common->clk_async)) + return PTR_ERR(common->clk_async); + + clk_prepare_enable(common->clk_async); + } pm_runtime_enable(dev); platform_set_drvdata(pdev, common); return 0; @@ -237,11 +372,6 @@ static int mtk_smi_common_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id mtk_smi_common_of_ids[] = { - { .compatible = "mediatek,mt8173-smi-common", }, - {} -}; - static struct platform_driver mtk_smi_common_driver = { .probe = mtk_smi_common_probe, .remove = mtk_smi_common_remove, @@ -272,4 +402,5 @@ err_unreg_smi: platform_driver_unregister(&mtk_smi_common_driver); return ret; } + subsys_initcall(mtk_smi_init); diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index af4884ba6b7c..869c83fb3c5d 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -20,7 +20,6 @@ #include <linux/ioport.h> #include <linux/spinlock.h> #include <linux/io.h> -#include <linux/module.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> @@ -398,7 +397,7 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p) gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4, GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay); gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4, - GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay); + GPMC_CONFIG4_WEEXTRADELAY, p->we_extra_delay); gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6, GPMC_CONFIG6_CYCLE2CYCLESAMECSEN, p->cycle2cyclesamecsen); @@ -1807,7 +1806,6 @@ static const struct of_device_id gpmc_dt_ids[] = { { .compatible = "ti,am3352-gpmc" }, /* am335x devices */ { } }; -MODULE_DEVICE_TABLE(of, gpmc_dt_ids); /** * gpmc_read_settings_dt - read gpmc settings from device-tree @@ -2134,8 +2132,7 @@ no_timings: /* is child a common bus? */ if (of_match_node(of_default_bus_match_table, child)) /* create children and other common bus children */ - if (of_platform_populate(child, of_default_bus_match_table, - NULL, &pdev->dev)) + if (of_platform_default_populate(child, NULL, &pdev->dev)) goto err_child_fail; return 0; @@ -2155,68 +2152,6 @@ err: return ret; } -static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - return 1; /* we're input only */ -} - -static int gpmc_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - return 0; /* we're input only */ -} - -static int gpmc_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - return -EINVAL; /* we're input only */ -} - -static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ -} - -static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - u32 reg; - - offset += 8; - - reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset); - - return !!reg; -} - -static int gpmc_gpio_init(struct gpmc_device *gpmc) -{ - int ret; - - gpmc->gpio_chip.parent = gpmc->dev; - gpmc->gpio_chip.owner = THIS_MODULE; - gpmc->gpio_chip.label = DEVICE_NAME; - gpmc->gpio_chip.ngpio = gpmc_nr_waitpins; - gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction; - gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input; - gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output; - gpmc->gpio_chip.set = gpmc_gpio_set; - gpmc->gpio_chip.get = gpmc_gpio_get; - gpmc->gpio_chip.base = -1; - - ret = gpiochip_add(&gpmc->gpio_chip); - if (ret < 0) { - dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret); - return ret; - } - - return 0; -} - -static void gpmc_gpio_exit(struct gpmc_device *gpmc) -{ - gpiochip_remove(&gpmc->gpio_chip); -} - static int gpmc_probe_dt(struct platform_device *pdev) { int ret; @@ -2281,7 +2216,69 @@ static int gpmc_probe_dt_children(struct platform_device *pdev) { return 0; } -#endif +#endif /* CONFIG_OF */ + +static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + return 1; /* we're input only */ +} + +static int gpmc_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return 0; /* we're input only */ +} + +static int gpmc_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + return -EINVAL; /* we're input only */ +} + +static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ +} + +static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + u32 reg; + + offset += 8; + + reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset); + + return !!reg; +} + +static int gpmc_gpio_init(struct gpmc_device *gpmc) +{ + int ret; + + gpmc->gpio_chip.parent = gpmc->dev; + gpmc->gpio_chip.owner = THIS_MODULE; + gpmc->gpio_chip.label = DEVICE_NAME; + gpmc->gpio_chip.ngpio = gpmc_nr_waitpins; + gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction; + gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input; + gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output; + gpmc->gpio_chip.set = gpmc_gpio_set; + gpmc->gpio_chip.get = gpmc_gpio_get; + gpmc->gpio_chip.base = -1; + + ret = gpiochip_add(&gpmc->gpio_chip); + if (ret < 0) { + dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret); + return ret; + } + + return 0; +} + +static void gpmc_gpio_exit(struct gpmc_device *gpmc) +{ + gpiochip_remove(&gpmc->gpio_chip); +} static int gpmc_probe(struct platform_device *pdev) { @@ -2437,15 +2434,7 @@ static __init int gpmc_init(void) { return platform_driver_register(&gpmc_driver); } - -static __exit void gpmc_exit(void) -{ - platform_driver_unregister(&gpmc_driver); - -} - postcore_initcall(gpmc_init); -module_exit(gpmc_exit); static struct omap3_gpmc_regs gpmc_context; diff --git a/drivers/memory/samsung/exynos-srom.c b/drivers/memory/samsung/exynos-srom.c index 96756fb4d6bd..bf827a666694 100644 --- a/drivers/memory/samsung/exynos-srom.c +++ b/drivers/memory/samsung/exynos-srom.c @@ -11,7 +11,7 @@ */ #include <linux/io.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_platform.h> @@ -91,17 +91,17 @@ static int exynos_srom_configure_bank(struct exynos_srom *srom, if (width == 2) cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT; - bw = __raw_readl(srom->reg_base + EXYNOS_SROM_BW); + bw = readl_relaxed(srom->reg_base + EXYNOS_SROM_BW); bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank); - __raw_writel(bw, srom->reg_base + EXYNOS_SROM_BW); + writel_relaxed(bw, srom->reg_base + EXYNOS_SROM_BW); - __raw_writel(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) | - (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) | - (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) | - (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) | - (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) | - (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT), - srom->reg_base + EXYNOS_SROM_BC0 + bank); + writel_relaxed(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) | + (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) | + (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) | + (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) | + (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) | + (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT), + srom->reg_base + EXYNOS_SROM_BC0 + bank); return 0; } @@ -134,7 +134,7 @@ static int exynos_srom_probe(struct platform_device *pdev) platform_set_drvdata(pdev, srom); srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets, - sizeof(exynos_srom_offsets)); + ARRAY_SIZE(exynos_srom_offsets)); if (!srom->reg_offset) { iounmap(srom->reg_base); return -ENOMEM; @@ -159,16 +159,6 @@ static int exynos_srom_probe(struct platform_device *pdev) return of_platform_populate(np, NULL, NULL, dev); } -static int exynos_srom_remove(struct platform_device *pdev) -{ - struct exynos_srom *srom = platform_get_drvdata(pdev); - - kfree(srom->reg_offset); - iounmap(srom->reg_base); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static void exynos_srom_save(void __iomem *base, struct exynos_srom_reg_dump *rd, @@ -211,21 +201,16 @@ static const struct of_device_id of_exynos_srom_ids[] = { }, {}, }; -MODULE_DEVICE_TABLE(of, of_exynos_srom_ids); static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume); static struct platform_driver exynos_srom_driver = { .probe = exynos_srom_probe, - .remove = exynos_srom_remove, .driver = { .name = "exynos-srom", .of_match_table = of_exynos_srom_ids, .pm = &exynos_srom_pm_ops, + .suppress_bind_attrs = true, }, }; -module_platform_driver(exynos_srom_driver); - -MODULE_AUTHOR("Pankaj Dubey <pankaj.dubey@samsung.com>"); -MODULE_DESCRIPTION("Exynos SROM Controller Driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(exynos_srom_driver); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a1ae0cc2b86d..a4803ac192bb 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -186,8 +186,10 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) timing = &mc->timings[i++]; err = load_one_timing(mc, timing, child); - if (err) + if (err) { + of_node_put(child); return err; + } } return 0; @@ -206,15 +208,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) for_each_child_of_node(mc->dev->of_node, node) { err = of_property_read_u32(node, "nvidia,ram-code", &node_ram_code); - if (err || (node_ram_code != ram_code)) { - of_node_put(node); + if (err || (node_ram_code != ram_code)) continue; - } err = load_timings(mc, node); + of_node_put(node); if (err) return err; - of_node_put(node); break; } diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 3dac7be39654..06cc781ebac1 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -970,8 +970,10 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, timing = &emc->timings[i++]; err = load_one_timing_from_dt(emc, timing, child); - if (err) + if (err) { + of_node_put(child); return err; + } } sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, @@ -995,10 +997,8 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) u32 value; err = of_property_read_u32(np, "nvidia,ram-code", &value); - if (err || (value != ram_code)) { - of_node_put(np); + if (err || (value != ram_code)) continue; - } return np; } |