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

khadas-mcu.c (3674B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for Khadas System control Microcontroller
      4 *
      5 * Copyright (C) 2020 BayLibre SAS
      6 *
      7 * Author(s): Neil Armstrong <narmstrong@baylibre.com>
      8 */
      9#include <linux/bitfield.h>
     10#include <linux/i2c.h>
     11#include <linux/mfd/core.h>
     12#include <linux/mfd/khadas-mcu.h>
     13#include <linux/module.h>
     14#include <linux/regmap.h>
     15
     16static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
     17{
     18	if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
     19	    reg < KHADAS_MCU_PWR_OFF_CMD_REG)
     20		return true;
     21
     22	switch (reg) {
     23	case KHADAS_MCU_PWR_OFF_CMD_REG:
     24	case KHADAS_MCU_PASSWD_START_REG:
     25	case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
     26	case KHADAS_MCU_CHECK_USER_PASSWD_REG:
     27	case KHADAS_MCU_WOL_INIT_START_REG:
     28	case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
     29		return true;
     30	default:
     31		return false;
     32	}
     33}
     34
     35static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
     36{
     37	switch (reg) {
     38	case KHADAS_MCU_PASSWD_VEN_0_REG:
     39	case KHADAS_MCU_PASSWD_VEN_1_REG:
     40	case KHADAS_MCU_PASSWD_VEN_2_REG:
     41	case KHADAS_MCU_PASSWD_VEN_3_REG:
     42	case KHADAS_MCU_PASSWD_VEN_4_REG:
     43	case KHADAS_MCU_PASSWD_VEN_5_REG:
     44	case KHADAS_MCU_MAC_0_REG:
     45	case KHADAS_MCU_MAC_1_REG:
     46	case KHADAS_MCU_MAC_2_REG:
     47	case KHADAS_MCU_MAC_3_REG:
     48	case KHADAS_MCU_MAC_4_REG:
     49	case KHADAS_MCU_MAC_5_REG:
     50	case KHADAS_MCU_USID_0_REG:
     51	case KHADAS_MCU_USID_1_REG:
     52	case KHADAS_MCU_USID_2_REG:
     53	case KHADAS_MCU_USID_3_REG:
     54	case KHADAS_MCU_USID_4_REG:
     55	case KHADAS_MCU_USID_5_REG:
     56	case KHADAS_MCU_VERSION_0_REG:
     57	case KHADAS_MCU_VERSION_1_REG:
     58	case KHADAS_MCU_DEVICE_NO_0_REG:
     59	case KHADAS_MCU_DEVICE_NO_1_REG:
     60	case KHADAS_MCU_FACTORY_TEST_REG:
     61	case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
     62		return false;
     63	default:
     64		return true;
     65	}
     66}
     67
     68static const struct regmap_config khadas_mcu_regmap_config = {
     69	.reg_bits	= 8,
     70	.reg_stride	= 1,
     71	.val_bits	= 8,
     72	.max_register	= KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
     73	.volatile_reg	= khadas_mcu_reg_volatile,
     74	.writeable_reg	= khadas_mcu_reg_writeable,
     75	.cache_type	= REGCACHE_RBTREE,
     76};
     77
     78static struct mfd_cell khadas_mcu_fan_cells[] = {
     79	/* VIM1/2 Rev13+ and VIM3 only */
     80	{ .name = "khadas-mcu-fan-ctrl", },
     81};
     82
     83static struct mfd_cell khadas_mcu_cells[] = {
     84	{ .name = "khadas-mcu-user-mem", },
     85};
     86
     87static int khadas_mcu_probe(struct i2c_client *client,
     88		       const struct i2c_device_id *id)
     89{
     90	struct device *dev = &client->dev;
     91	struct khadas_mcu *ddata;
     92	int ret;
     93
     94	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
     95	if (!ddata)
     96		return -ENOMEM;
     97
     98	i2c_set_clientdata(client, ddata);
     99
    100	ddata->dev = dev;
    101
    102	ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
    103	if (IS_ERR(ddata->regmap)) {
    104		ret = PTR_ERR(ddata->regmap);
    105		dev_err(dev, "Failed to allocate register map: %d\n", ret);
    106		return ret;
    107	}
    108
    109	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
    110				   khadas_mcu_cells,
    111				   ARRAY_SIZE(khadas_mcu_cells),
    112				   NULL, 0, NULL);
    113	if (ret)
    114		return ret;
    115
    116	if (of_find_property(dev->of_node, "#cooling-cells", NULL))
    117		return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
    118					    khadas_mcu_fan_cells,
    119					    ARRAY_SIZE(khadas_mcu_fan_cells),
    120					    NULL, 0, NULL);
    121
    122	return 0;
    123}
    124
    125#ifdef CONFIG_OF
    126static const struct of_device_id khadas_mcu_of_match[] = {
    127	{ .compatible = "khadas,mcu", },
    128	{},
    129};
    130MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
    131#endif
    132
    133static struct i2c_driver khadas_mcu_driver = {
    134	.driver = {
    135		.name = "khadas-mcu-core",
    136		.of_match_table = of_match_ptr(khadas_mcu_of_match),
    137	},
    138	.probe = khadas_mcu_probe,
    139};
    140module_i2c_driver(khadas_mcu_driver);
    141
    142MODULE_DESCRIPTION("Khadas MCU core driver");
    143MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    144MODULE_LICENSE("GPL v2");