166 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI da8xx DDR2/mDDR controller driver4 *5 * Copyright (C) 2016 BayLibre SAS6 *7 * Author:8 * Bartosz Golaszewski <bgolaszewski@baylibre.com>9 */10 11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/io.h>15 16/*17 * REVISIT: Linux doesn't have a good framework for the kind of performance18 * knobs this driver controls. We can't use device tree properties as it deals19 * with hardware configuration rather than description. We also don't want to20 * commit to maintaining some random sysfs attributes.21 *22 * For now we just hardcode the register values for the boards that need23 * some changes (as is the case for the LCD controller on da850-lcdk - the24 * first board we support here). When linux gets an appropriate framework,25 * we'll easily convert the driver to it.26 */27 28struct da8xx_ddrctl_config_knob {29 const char *name;30 u32 reg;31 u32 mask;32 u32 shift;33};34 35static const struct da8xx_ddrctl_config_knob da8xx_ddrctl_knobs[] = {36 {37 .name = "da850-pbbpr",38 .reg = 0x20,39 .mask = 0xffffff00,40 .shift = 0,41 },42};43 44struct da8xx_ddrctl_setting {45 const char *name;46 u32 val;47};48 49struct da8xx_ddrctl_board_settings {50 const char *board;51 const struct da8xx_ddrctl_setting *settings;52};53 54static const struct da8xx_ddrctl_setting da850_lcdk_ddrctl_settings[] = {55 {56 .name = "da850-pbbpr",57 .val = 0x20,58 },59 { }60};61 62static const struct da8xx_ddrctl_board_settings da8xx_ddrctl_board_confs[] = {63 {64 .board = "ti,da850-lcdk",65 .settings = da850_lcdk_ddrctl_settings,66 },67};68 69static const struct da8xx_ddrctl_config_knob *70da8xx_ddrctl_match_knob(const struct da8xx_ddrctl_setting *setting)71{72 const struct da8xx_ddrctl_config_knob *knob;73 int i;74 75 for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_knobs); i++) {76 knob = &da8xx_ddrctl_knobs[i];77 78 if (strcmp(knob->name, setting->name) == 0)79 return knob;80 }81 82 return NULL;83}84 85static const struct da8xx_ddrctl_setting *da8xx_ddrctl_get_board_settings(void)86{87 const struct da8xx_ddrctl_board_settings *board_settings;88 int i;89 90 for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_board_confs); i++) {91 board_settings = &da8xx_ddrctl_board_confs[i];92 93 if (of_machine_is_compatible(board_settings->board))94 return board_settings->settings;95 }96 97 return NULL;98}99 100static int da8xx_ddrctl_probe(struct platform_device *pdev)101{102 const struct da8xx_ddrctl_config_knob *knob;103 const struct da8xx_ddrctl_setting *setting;104 struct resource *res;105 void __iomem *ddrctl;106 struct device *dev;107 u32 reg;108 109 dev = &pdev->dev;110 111 setting = da8xx_ddrctl_get_board_settings();112 if (!setting) {113 dev_err(dev, "no settings defined for this board\n");114 return -EINVAL;115 }116 117 ddrctl = devm_platform_get_and_ioremap_resource(pdev, 0, &res);118 if (IS_ERR(ddrctl)) {119 dev_err(dev, "unable to map memory controller registers\n");120 return PTR_ERR(ddrctl);121 }122 123 for (; setting->name; setting++) {124 knob = da8xx_ddrctl_match_knob(setting);125 if (!knob) {126 dev_warn(dev,127 "no such config option: %s\n", setting->name);128 continue;129 }130 131 if (knob->reg + sizeof(u32) > resource_size(res)) {132 dev_warn(dev,133 "register offset of '%s' exceeds mapped memory size\n",134 knob->name);135 continue;136 }137 138 reg = readl(ddrctl + knob->reg);139 reg &= knob->mask;140 reg |= setting->val << knob->shift;141 142 dev_dbg(dev, "writing 0x%08x to %s\n", reg, setting->name);143 144 writel(reg, ddrctl + knob->reg);145 }146 147 return 0;148}149 150static const struct of_device_id da8xx_ddrctl_of_match[] = {151 { .compatible = "ti,da850-ddr-controller", },152 { },153};154 155static struct platform_driver da8xx_ddrctl_driver = {156 .probe = da8xx_ddrctl_probe,157 .driver = {158 .name = "da850-ddr-controller",159 .of_match_table = da8xx_ddrctl_of_match,160 },161};162module_platform_driver(da8xx_ddrctl_driver);163 164MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");165MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver");166