0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/io.h>
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 struct da8xx_ddrctl_config_knob {
0030 const char *name;
0031 u32 reg;
0032 u32 mask;
0033 u32 shift;
0034 };
0035
0036 static const struct da8xx_ddrctl_config_knob da8xx_ddrctl_knobs[] = {
0037 {
0038 .name = "da850-pbbpr",
0039 .reg = 0x20,
0040 .mask = 0xffffff00,
0041 .shift = 0,
0042 },
0043 };
0044
0045 struct da8xx_ddrctl_setting {
0046 const char *name;
0047 u32 val;
0048 };
0049
0050 struct da8xx_ddrctl_board_settings {
0051 const char *board;
0052 const struct da8xx_ddrctl_setting *settings;
0053 };
0054
0055 static const struct da8xx_ddrctl_setting da850_lcdk_ddrctl_settings[] = {
0056 {
0057 .name = "da850-pbbpr",
0058 .val = 0x20,
0059 },
0060 { }
0061 };
0062
0063 static const struct da8xx_ddrctl_board_settings da8xx_ddrctl_board_confs[] = {
0064 {
0065 .board = "ti,da850-lcdk",
0066 .settings = da850_lcdk_ddrctl_settings,
0067 },
0068 };
0069
0070 static const struct da8xx_ddrctl_config_knob *
0071 da8xx_ddrctl_match_knob(const struct da8xx_ddrctl_setting *setting)
0072 {
0073 const struct da8xx_ddrctl_config_knob *knob;
0074 int i;
0075
0076 for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_knobs); i++) {
0077 knob = &da8xx_ddrctl_knobs[i];
0078
0079 if (strcmp(knob->name, setting->name) == 0)
0080 return knob;
0081 }
0082
0083 return NULL;
0084 }
0085
0086 static const struct da8xx_ddrctl_setting *da8xx_ddrctl_get_board_settings(void)
0087 {
0088 const struct da8xx_ddrctl_board_settings *board_settings;
0089 int i;
0090
0091 for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_board_confs); i++) {
0092 board_settings = &da8xx_ddrctl_board_confs[i];
0093
0094 if (of_machine_is_compatible(board_settings->board))
0095 return board_settings->settings;
0096 }
0097
0098 return NULL;
0099 }
0100
0101 static int da8xx_ddrctl_probe(struct platform_device *pdev)
0102 {
0103 const struct da8xx_ddrctl_config_knob *knob;
0104 const struct da8xx_ddrctl_setting *setting;
0105 struct resource *res;
0106 void __iomem *ddrctl;
0107 struct device *dev;
0108 u32 reg;
0109
0110 dev = &pdev->dev;
0111
0112 setting = da8xx_ddrctl_get_board_settings();
0113 if (!setting) {
0114 dev_err(dev, "no settings defined for this board\n");
0115 return -EINVAL;
0116 }
0117
0118 ddrctl = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0119 if (IS_ERR(ddrctl)) {
0120 dev_err(dev, "unable to map memory controller registers\n");
0121 return PTR_ERR(ddrctl);
0122 }
0123
0124 for (; setting->name; setting++) {
0125 knob = da8xx_ddrctl_match_knob(setting);
0126 if (!knob) {
0127 dev_warn(dev,
0128 "no such config option: %s\n", setting->name);
0129 continue;
0130 }
0131
0132 if (knob->reg + sizeof(u32) > resource_size(res)) {
0133 dev_warn(dev,
0134 "register offset of '%s' exceeds mapped memory size\n",
0135 knob->name);
0136 continue;
0137 }
0138
0139 reg = readl(ddrctl + knob->reg);
0140 reg &= knob->mask;
0141 reg |= setting->val << knob->shift;
0142
0143 dev_dbg(dev, "writing 0x%08x to %s\n", reg, setting->name);
0144
0145 writel(reg, ddrctl + knob->reg);
0146 }
0147
0148 return 0;
0149 }
0150
0151 static const struct of_device_id da8xx_ddrctl_of_match[] = {
0152 { .compatible = "ti,da850-ddr-controller", },
0153 { },
0154 };
0155
0156 static struct platform_driver da8xx_ddrctl_driver = {
0157 .probe = da8xx_ddrctl_probe,
0158 .driver = {
0159 .name = "da850-ddr-controller",
0160 .of_match_table = da8xx_ddrctl_of_match,
0161 },
0162 };
0163 module_platform_driver(da8xx_ddrctl_driver);
0164
0165 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
0166 MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver");
0167 MODULE_LICENSE("GPL v2");