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

core.c (4751B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Core driver for Wilco Embedded Controller
      4 *
      5 * Copyright 2018 Google LLC
      6 *
      7 * This is the entry point for the drivers that control the Wilco EC.
      8 */
      9
     10#include <linux/acpi.h>
     11#include <linux/device.h>
     12#include <linux/ioport.h>
     13#include <linux/module.h>
     14#include <linux/platform_data/wilco-ec.h>
     15#include <linux/platform_device.h>
     16
     17#include "../cros_ec_lpc_mec.h"
     18
     19#define DRV_NAME "wilco-ec"
     20
     21static struct resource *wilco_get_resource(struct platform_device *pdev,
     22					   int index)
     23{
     24	struct device *dev = &pdev->dev;
     25	struct resource *res;
     26
     27	res = platform_get_resource(pdev, IORESOURCE_IO, index);
     28	if (!res) {
     29		dev_dbg(dev, "Couldn't find IO resource %d\n", index);
     30		return res;
     31	}
     32
     33	return devm_request_region(dev, res->start, resource_size(res),
     34				   dev_name(dev));
     35}
     36
     37static int wilco_ec_probe(struct platform_device *pdev)
     38{
     39	struct device *dev = &pdev->dev;
     40	struct wilco_ec_device *ec;
     41	int ret;
     42
     43	ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
     44	if (!ec)
     45		return -ENOMEM;
     46
     47	platform_set_drvdata(pdev, ec);
     48	ec->dev = dev;
     49	mutex_init(&ec->mailbox_lock);
     50
     51	ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE;
     52	ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
     53	if (!ec->data_buffer)
     54		return -ENOMEM;
     55
     56	/* Prepare access to IO regions provided by ACPI */
     57	ec->io_data = wilco_get_resource(pdev, 0);	/* Host Data */
     58	ec->io_command = wilco_get_resource(pdev, 1);	/* Host Command */
     59	ec->io_packet = wilco_get_resource(pdev, 2);	/* MEC EMI */
     60	if (!ec->io_data || !ec->io_command || !ec->io_packet)
     61		return -ENODEV;
     62
     63	/* Initialize cros_ec register interface for communication */
     64	cros_ec_lpc_mec_init(ec->io_packet->start,
     65			     ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
     66
     67	/*
     68	 * Register a child device that will be found by the debugfs driver.
     69	 * Ignore failure.
     70	 */
     71	ec->debugfs_pdev = platform_device_register_data(dev,
     72							 "wilco-ec-debugfs",
     73							 PLATFORM_DEVID_AUTO,
     74							 NULL, 0);
     75
     76	/* Register a child device that will be found by the RTC driver. */
     77	ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec",
     78						     PLATFORM_DEVID_AUTO,
     79						     NULL, 0);
     80	if (IS_ERR(ec->rtc_pdev)) {
     81		dev_err(dev, "Failed to create RTC platform device\n");
     82		ret = PTR_ERR(ec->rtc_pdev);
     83		goto unregister_debugfs;
     84	}
     85
     86	/* Set up the keyboard backlight LEDs. */
     87	ret = wilco_keyboard_leds_init(ec);
     88	if (ret < 0) {
     89		dev_err(dev,
     90			"Failed to initialize keyboard LEDs: %d\n",
     91			ret);
     92		goto unregister_rtc;
     93	}
     94
     95	ret = wilco_ec_add_sysfs(ec);
     96	if (ret < 0) {
     97		dev_err(dev, "Failed to create sysfs entries: %d\n", ret);
     98		goto unregister_rtc;
     99	}
    100
    101	/* Register child device to be found by charger config driver. */
    102	ec->charger_pdev = platform_device_register_data(dev, "wilco-charger",
    103							 PLATFORM_DEVID_AUTO,
    104							 NULL, 0);
    105	if (IS_ERR(ec->charger_pdev)) {
    106		dev_err(dev, "Failed to create charger platform device\n");
    107		ret = PTR_ERR(ec->charger_pdev);
    108		goto remove_sysfs;
    109	}
    110
    111	/* Register child device that will be found by the telemetry driver. */
    112	ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
    113						       PLATFORM_DEVID_AUTO,
    114						       ec, sizeof(*ec));
    115	if (IS_ERR(ec->telem_pdev)) {
    116		dev_err(dev, "Failed to create telemetry platform device\n");
    117		ret = PTR_ERR(ec->telem_pdev);
    118		goto unregister_charge_config;
    119	}
    120
    121	return 0;
    122
    123unregister_charge_config:
    124	platform_device_unregister(ec->charger_pdev);
    125remove_sysfs:
    126	wilco_ec_remove_sysfs(ec);
    127unregister_rtc:
    128	platform_device_unregister(ec->rtc_pdev);
    129unregister_debugfs:
    130	if (ec->debugfs_pdev)
    131		platform_device_unregister(ec->debugfs_pdev);
    132	cros_ec_lpc_mec_destroy();
    133	return ret;
    134}
    135
    136static int wilco_ec_remove(struct platform_device *pdev)
    137{
    138	struct wilco_ec_device *ec = platform_get_drvdata(pdev);
    139
    140	platform_device_unregister(ec->telem_pdev);
    141	platform_device_unregister(ec->charger_pdev);
    142	wilco_ec_remove_sysfs(ec);
    143	platform_device_unregister(ec->rtc_pdev);
    144	if (ec->debugfs_pdev)
    145		platform_device_unregister(ec->debugfs_pdev);
    146
    147	/* Teardown cros_ec interface */
    148	cros_ec_lpc_mec_destroy();
    149
    150	return 0;
    151}
    152
    153static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
    154	{ "GOOG000C", 0 },
    155	{ }
    156};
    157MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
    158
    159static struct platform_driver wilco_ec_driver = {
    160	.driver = {
    161		.name = DRV_NAME,
    162		.acpi_match_table = wilco_ec_acpi_device_ids,
    163	},
    164	.probe = wilco_ec_probe,
    165	.remove = wilco_ec_remove,
    166};
    167
    168module_platform_driver(wilco_ec_driver);
    169
    170MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
    171MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>");
    172MODULE_LICENSE("GPL v2");
    173MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");
    174MODULE_ALIAS("platform:" DRV_NAME);