1/* 2 * ocp.h 3 * 4 * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org) 5 * Mipsys - France 6 * 7 * Derived from work (c) Armin Kuster akuster@pacbell.net 8 * 9 * Additional support and port to 2.6 LDM/sysfs by 10 * Matt Porter <mporter@kernel.crashing.org> 11 * Copyright 2003-2004 MontaVista Software, Inc. 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 * 18 * TODO: - Add get/put interface & fixup locking to provide same API for 19 * 2.4 and 2.5 20 * - Rework PM callbacks 21 */ 22 23#ifdef __KERNEL__ 24#ifndef __OCP_H__ 25#define __OCP_H__ 26 27#include <linux/init.h> 28#include <linux/list.h> 29#include <linux/device.h> 30 31#include <asm/mmu.h> 32#include <asm/ocp_ids.h> 33#include <asm/rwsem.h> 34#include <asm/semaphore.h> 35 36#ifdef CONFIG_PPC_OCP 37 38#define OCP_MAX_IRQS 7 39#define MAX_EMACS 4 40#define OCP_IRQ_NA -1 /* used when ocp device does not have an irq */ 41#define OCP_IRQ_MUL -2 /* used for ocp devices with multiply irqs */ 42#define OCP_NULL_TYPE -1 /* used to mark end of list */ 43#define OCP_CPM_NA 0 /* No Clock or Power Management avaliable */ 44#define OCP_PADDR_NA 0 /* No MMIO registers */ 45 46#define OCP_ANY_ID (~0) 47#define OCP_ANY_INDEX -1 48 49extern struct list_head ocp_devices; 50extern struct rw_semaphore ocp_devices_sem; 51 52struct ocp_device_id { 53 unsigned int vendor, function; /* Vendor and function ID or OCP_ANY_ID */ 54 unsigned long driver_data; /* Data private to the driver */ 55}; 56 57 58/* 59 * Static definition of an OCP device. 60 * 61 * @vendor: Vendor code. It is _STRONGLY_ discouraged to use 62 * the vendor code as a way to match a unique device, 63 * though I kept that possibility open, you should 64 * really define different function codes for different 65 * device types 66 * @function: This is the function code for this device. 67 * @index: This index is used for mapping the Nth function of a 68 * given core. This is typically used for cross-driver 69 * matching, like looking for a given MAL or ZMII from 70 * an EMAC or for getting to the proper set of DCRs. 71 * Indices are no longer magically calculated based on 72 * structure ordering, they have to be actually coded 73 * into the ocp_def to avoid any possible confusion 74 * I _STRONGLY_ (again ? wow !) encourage anybody relying 75 * on index mapping to encode the "target" index in an 76 * associated structure pointed to by "additions", see 77 * how it's done for the EMAC driver. 78 * @paddr: Device physical address (may not mean anything...) 79 * @irq: Interrupt line for this device (TODO: think about making 80 * an array with this) 81 * @pm: Currently, contains the bitmask in CPMFR DCR for the device 82 * @additions: Optionally points to a function specific structure 83 * providing additional informations for a given device 84 * instance. It's currently used by the EMAC driver for MAL 85 * channel & ZMII port mapping among others. 86 * @show: Optionally points to a function specific structure 87 * providing a sysfs show routine for additions fields. 88 */ 89struct ocp_def { 90 unsigned int vendor; 91 unsigned int function; 92 int index; 93 phys_addr_t paddr; 94 int irq; 95 unsigned long pm; 96 void *additions; 97 void (*show)(struct device *); 98}; 99 100 101/* Struct for a given device instance */ 102struct ocp_device { 103 struct list_head link; 104 char name[80]; /* device name */ 105 struct ocp_def *def; /* device definition */ 106 void *drvdata; /* driver data for this device */ 107 struct ocp_driver *driver; 108 u32 current_state; /* Current operating state. In ACPI-speak, 109 this is D0-D3, D0 being fully functional, 110 and D3 being off. */ 111 struct device dev; 112}; 113 114struct ocp_driver { 115 struct list_head node; 116 char *name; 117 const struct ocp_device_id *id_table; /* NULL if wants all devices */ 118 int (*probe) (struct ocp_device *dev); /* New device inserted */ 119 void (*remove) (struct ocp_device *dev); /* Device removed (NULL if not a hot-plug capable driver) */ 120 int (*suspend) (struct ocp_device *dev, pm_message_t state); /* Device suspended */ 121 int (*resume) (struct ocp_device *dev); /* Device woken up */ 122 struct device_driver driver; 123}; 124 125#define to_ocp_dev(n) container_of(n, struct ocp_device, dev) 126#define to_ocp_drv(n) container_of(n, struct ocp_driver, driver) 127 128/* Similar to the helpers above, these manipulate per-ocp_dev 129 * driver-specific data. Currently stored as ocp_dev::ocpdev, 130 * a void pointer, but it is not present on older kernels. 131 */ 132static inline void * 133ocp_get_drvdata(struct ocp_device *pdev) 134{ 135 return pdev->drvdata; 136} 137 138static inline void 139ocp_set_drvdata(struct ocp_device *pdev, void *data) 140{ 141 pdev->drvdata = data; 142} 143 144#if defined(CONFIG_PM) 145/* 146 * This is right for the IBM 405 and 440 but will need to be 147 * generalized if the OCP stuff gets used on other processors. 148 */ 149static inline void 150ocp_force_power_off(struct ocp_device *odev) 151{ 152 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | odev->def->pm); 153} 154 155static inline void 156ocp_force_power_on(struct ocp_device *odev) 157{ 158 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~odev->def->pm); 159} 160#else 161#define ocp_force_power_off(x) (void)(x) 162#define ocp_force_power_on(x) (void)(x) 163#endif 164 165/* Register/Unregister an OCP driver */ 166extern int ocp_register_driver(struct ocp_driver *drv); 167extern void ocp_unregister_driver(struct ocp_driver *drv); 168 169/* Build list of devices */ 170extern int ocp_early_init(void) __init; 171 172/* Find a device by index */ 173extern struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index); 174 175/* Get a def by index */ 176extern struct ocp_def *ocp_get_one_device(unsigned int vendor, unsigned int function, int index); 177 178/* Add a device by index */ 179extern int ocp_add_one_device(struct ocp_def *def); 180 181/* Remove a device by index */ 182extern int ocp_remove_one_device(unsigned int vendor, unsigned int function, int index); 183 184/* Iterate over devices and execute a routine */ 185extern void ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg); 186 187/* Sysfs support */ 188#define OCP_SYSFS_ADDTL(type, format, name, field) \ 189static ssize_t \ 190show_##name##_##field(struct device *dev, struct device_attribute *attr, char *buf) \ 191{ \ 192 struct ocp_device *odev = to_ocp_dev(dev); \ 193 type *add = odev->def->additions; \ 194 \ 195 return sprintf(buf, format, add->field); \ 196} \ 197static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL); 198 199#ifdef CONFIG_IBM_OCP 200#include <asm/ibm_ocp.h> 201#endif 202 203#endif /* CONFIG_PPC_OCP */ 204#endif /* __OCP_H__ */ 205#endif /* __KERNEL__ */ 206