Skip to content

Commit

Permalink
Merge branch 'acpi-lpss'
Browse files Browse the repository at this point in the history
* acpi-lpss:
  ACPI / platform: create LPSS clocks if Lynxpoint devices are found during scan
  clk: x86: add support for Lynxpoint LPSS clocks
  x86: add support for Intel Low Power Subsystem
  ACPI / platform: fix comment about the platform device name
  ACPI: add support for CSRT table
  • Loading branch information
Rafael J. Wysocki committed Feb 11, 2013
2 parents a9834cb + e375325 commit 17b1639
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 13 deletions.
10 changes: 10 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,16 @@ config X86_MDFLD

endif

config X86_INTEL_LPSS
bool "Intel Low Power Subsystem Support"
depends on ACPI
select COMMON_CLK
---help---
Select to build support for Intel Low Power Subsystem such as
found on Intel Lynxpoint PCH. Selecting this option enables
things like clock tree (common clock framework) which are needed
by the LPSS peripheral drivers.

config X86_RDC321X
bool "RDC R-321x SoC"
depends on X86_32
Expand Down
1 change: 1 addition & 0 deletions drivers/acpi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y += csrt.o
acpi-y += acpi_platform.o
acpi-y += power.o
acpi-y += event.o
Expand Down
27 changes: 25 additions & 2 deletions drivers/acpi/acpi_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
Expand All @@ -21,17 +22,34 @@

ACPI_MODULE_NAME("platform");

static int acpi_create_platform_clks(struct acpi_device *adev)
{
static struct platform_device *pdev;

/* Create Lynxpoint LPSS clocks */
if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
}

return 0;
}

/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
* @flags: ACPI_PLATFORM_* flags that affect the creation of the platform
* devices.
*
* Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common
* resources and returns a pointer to it. Otherwise, return %NULL.
*
* The platform device's name will be taken from the @adev's _HID and _UID.
* Name of the platform device will be the same as @adev's.
*/
struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
unsigned long flags)
{
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
Expand All @@ -41,6 +59,11 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
struct resource *resources;
int count;

if ((flags & ACPI_PLATFORM_CLK) && acpi_create_platform_clks(adev)) {
dev_err(&adev->dev, "failed to create clocks\n");
return NULL;
}

/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
return NULL;
Expand Down
159 changes: 159 additions & 0 deletions drivers/acpi/csrt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Support for Core System Resources Table (CSRT)
*
* Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#define pr_fmt(fmt) "ACPI: CSRT: " fmt

#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>

ACPI_MODULE_NAME("CSRT");

static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev,
const struct acpi_csrt_group *grp)
{
const struct acpi_csrt_shared_info *si;
struct resource res[3];
size_t nres;
int ret;

memset(res, 0, sizeof(res));
nres = 0;

si = (const struct acpi_csrt_shared_info *)&grp[1];
/*
* The peripherals that are listed on CSRT typically support only
* 32-bit addresses so we only use the low part of MMIO base for
* now.
*/
if (!si->mmio_base_high && si->mmio_base_low) {
/*
* There is no size of the memory resource in shared_info
* so we assume that it is 4k here.
*/
res[nres].start = si->mmio_base_low;
res[nres].end = res[0].start + SZ_4K - 1;
res[nres++].flags = IORESOURCE_MEM;
}

if (si->gsi_interrupt) {
int irq = acpi_register_gsi(NULL, si->gsi_interrupt,
si->interrupt_mode,
si->interrupt_polarity);
res[nres].start = irq;
res[nres].end = irq;
res[nres++].flags = IORESOURCE_IRQ;
}

if (si->base_request_line || si->num_handshake_signals) {
/*
* We pass the driver a DMA resource describing the range
* of request lines the device supports.
*/
res[nres].start = si->base_request_line;
res[nres].end = res[nres].start + si->num_handshake_signals - 1;
res[nres++].flags = IORESOURCE_DMA;
}

ret = platform_device_add_resources(pdev, res, nres);
if (ret) {
if (si->gsi_interrupt)
acpi_unregister_gsi(si->gsi_interrupt);
return ret;
}

return 0;
}

static int __init
acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp)
{
struct platform_device *pdev;
char vendor[5], name[16];
int ret, i;

vendor[0] = grp->vendor_id;
vendor[1] = grp->vendor_id >> 8;
vendor[2] = grp->vendor_id >> 16;
vendor[3] = grp->vendor_id >> 24;
vendor[4] = '\0';

if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
return -ENODEV;

snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id);
pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;

/* Add resources based on the shared info */
ret = acpi_csrt_parse_shared_info(pdev, grp);
if (ret)
goto fail;

ret = platform_device_add(pdev);
if (ret)
goto fail;

for (i = 0; i < pdev->num_resources; i++)
dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]);

return 0;

fail:
platform_device_put(pdev);
return ret;
}

/*
* CSRT or Core System Resources Table is a proprietary ACPI table
* introduced by Microsoft. This table can contain devices that are not in
* the system DSDT table. In particular DMA controllers might be described
* here.
*
* We present these devices as normal platform devices that don't have ACPI
* IDs or handle. The platform device name will be something like
* <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto.
*/
void __init acpi_csrt_init(void)
{
struct acpi_csrt_group *grp, *end;
struct acpi_table_csrt *csrt;
acpi_status status;
int ret;

status = acpi_get_table(ACPI_SIG_CSRT, 0,
(struct acpi_table_header **)&csrt);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
pr_warn("failed to get the CSRT table\n");
return;
}

pr_debug("parsing CSRT table for devices\n");

grp = (struct acpi_csrt_group *)(csrt + 1);
end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);

while (grp < end) {
ret = acpi_csrt_parse_resource_group(grp);
if (ret) {
pr_warn("error in parsing resource group: %d\n", ret);
return;
}

grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
}
}
7 changes: 6 additions & 1 deletion drivers/acpi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
int init_acpi_device_notify(void);
int acpi_scan_init(void);
int acpi_sysfs_init(void);
void acpi_csrt_init(void);

#ifdef CONFIG_DEBUG_FS
extern struct dentry *acpi_debugfs_dir;
Expand Down Expand Up @@ -117,6 +118,10 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;

struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
/* Flags for acpi_create_platform_device */
#define ACPI_PLATFORM_CLK BIT(0)

struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
unsigned long flags);

#endif /* _ACPI_INTERNAL_H_ */
23 changes: 13 additions & 10 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
{ "PNP0D40" },

/* Haswell LPSS devices */
{ "INT33C0", 0 },
{ "INT33C1", 0 },
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT33C4", 0 },
{ "INT33C5", 0 },
{ "INT33C6", 0 },
{ "INT33C7", 0 },
{ "INT33C0", ACPI_PLATFORM_CLK },
{ "INT33C1", ACPI_PLATFORM_CLK },
{ "INT33C2", ACPI_PLATFORM_CLK },
{ "INT33C3", ACPI_PLATFORM_CLK },
{ "INT33C4", ACPI_PLATFORM_CLK },
{ "INT33C5", ACPI_PLATFORM_CLK },
{ "INT33C6", ACPI_PLATFORM_CLK },
{ "INT33C7", ACPI_PLATFORM_CLK },

{ }
};
Expand Down Expand Up @@ -1578,6 +1578,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
{
const struct acpi_device_id *id;
acpi_status status = AE_OK;
struct acpi_device *device;
unsigned long long sta_not_used;
Expand All @@ -1593,9 +1594,10 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
if (acpi_bus_get_device(handle, &device))
return AE_CTRL_DEPTH;

if (!acpi_match_device_ids(device, acpi_platform_device_ids)) {
id = __acpi_match_device(device, acpi_platform_device_ids);
if (id) {
/* This is a known good platform device. */
acpi_create_platform_device(device);
acpi_create_platform_device(device, id->driver_data);
} else if (device_attach(&device->dev) < 0) {
status = AE_CTRL_DEPTH;
}
Expand Down Expand Up @@ -1717,6 +1719,7 @@ int __init acpi_scan_init(void)
}

acpi_pci_root_init();
acpi_csrt_init();

/*
* Enumerate devices in the ACPI namespace.
Expand Down
1 change: 1 addition & 0 deletions drivers/clk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
obj-$(CONFIG_X86) += x86/

# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
Expand Down
2 changes: 2 additions & 0 deletions drivers/clk/x86/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
clk-x86-lpss-objs := clk-lpss.o clk-lpt.o
obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o
Loading

0 comments on commit 17b1639

Please sign in to comment.