cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

da8xx-ddrctl.c (3949B)


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