Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SS4200-E Hardware API
0004  * Copyright (c) 2009, Intel Corporation.
0005  * Copyright IBM Corporation, 2009
0006  *
0007  * Author: Dave Hansen <dave@sr71.net>
0008  */
0009 
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011 
0012 #include <linux/dmi.h>
0013 #include <linux/init.h>
0014 #include <linux/ioport.h>
0015 #include <linux/kernel.h>
0016 #include <linux/leds.h>
0017 #include <linux/module.h>
0018 #include <linux/pci.h>
0019 #include <linux/types.h>
0020 #include <linux/uaccess.h>
0021 
0022 MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
0023 MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
0024 MODULE_LICENSE("GPL");
0025 
0026 /*
0027  * ICH7 LPC/GPIO PCI Config register offsets
0028  */
0029 #define PMBASE      0x040
0030 #define GPIO_BASE   0x048
0031 #define GPIO_CTRL   0x04c
0032 #define GPIO_EN     0x010
0033 
0034 /*
0035  * The ICH7 GPIO register block is 64 bytes in size.
0036  */
0037 #define ICH7_GPIO_SIZE  64
0038 
0039 /*
0040  * Define register offsets within the ICH7 register block.
0041  */
0042 #define GPIO_USE_SEL    0x000
0043 #define GP_IO_SEL   0x004
0044 #define GP_LVL      0x00c
0045 #define GPO_BLINK   0x018
0046 #define GPI_INV     0x030
0047 #define GPIO_USE_SEL2   0x034
0048 #define GP_IO_SEL2  0x038
0049 #define GP_LVL2     0x03c
0050 
0051 /*
0052  * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
0053  */
0054 static const struct pci_device_id ich7_lpc_pci_id[] = {
0055     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
0056     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
0057     { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
0058     { } /* NULL entry */
0059 };
0060 
0061 MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
0062 
0063 static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
0064 {
0065     pr_info("detected '%s'\n", id->ident);
0066     return 1;
0067 }
0068 
0069 static bool nodetect;
0070 module_param_named(nodetect, nodetect, bool, 0);
0071 MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
0072 
0073 /*
0074  * struct nas_led_whitelist - List of known good models
0075  *
0076  * Contains the known good models this driver is compatible with.
0077  * When adding a new model try to be as strict as possible. This
0078  * makes it possible to keep the false positives (the model is
0079  * detected as working, but in reality it is not) as low as
0080  * possible.
0081  */
0082 static const struct dmi_system_id nas_led_whitelist[] __initconst = {
0083     {
0084         .callback = ss4200_led_dmi_callback,
0085         .ident = "Intel SS4200-E",
0086         .matches = {
0087             DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
0088             DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
0089             DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
0090         }
0091     },
0092     {
0093         /*
0094          * FUJITSU SIEMENS SCALEO Home Server/SS4200-E
0095          * BIOS V090L 12/19/2007
0096          */
0097         .callback = ss4200_led_dmi_callback,
0098         .ident = "Fujitsu Siemens SCALEO Home Server",
0099         .matches = {
0100             DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
0101             DMI_MATCH(DMI_PRODUCT_NAME, "SCALEO Home Server"),
0102             DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
0103         }
0104     },
0105     {}
0106 };
0107 
0108 /*
0109  * Base I/O address assigned to the Power Management register block
0110  */
0111 static u32 g_pm_io_base;
0112 
0113 /*
0114  * Base I/O address assigned to the ICH7 GPIO register block
0115  */
0116 static u32 nas_gpio_io_base;
0117 
0118 /*
0119  * When we successfully register a region, we are returned a resource.
0120  * We use these to identify which regions we need to release on our way
0121  * back out.
0122  */
0123 static struct resource *gp_gpio_resource;
0124 
0125 struct nasgpio_led {
0126     char *name;
0127     u32 gpio_bit;
0128     struct led_classdev led_cdev;
0129 };
0130 
0131 /*
0132  * gpio_bit(s) are the ICH7 GPIO bit assignments
0133  */
0134 static struct nasgpio_led nasgpio_leds[] = {
0135     { .name = "hdd1:blue:sata", .gpio_bit = 0 },
0136     { .name = "hdd1:amber:sata",    .gpio_bit = 1 },
0137     { .name = "hdd2:blue:sata", .gpio_bit = 2 },
0138     { .name = "hdd2:amber:sata",    .gpio_bit = 3 },
0139     { .name = "hdd3:blue:sata", .gpio_bit = 4 },
0140     { .name = "hdd3:amber:sata",    .gpio_bit = 5 },
0141     { .name = "hdd4:blue:sata", .gpio_bit = 6 },
0142     { .name = "hdd4:amber:sata",    .gpio_bit = 7 },
0143     { .name = "power:blue:power",   .gpio_bit = 27},
0144     { .name = "power:amber:power",  .gpio_bit = 28},
0145 };
0146 
0147 #define NAS_RECOVERY    0x00000400  /* GPIO10 */
0148 
0149 static struct nasgpio_led *
0150 led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
0151 {
0152     return container_of(led_cdev, struct nasgpio_led, led_cdev);
0153 }
0154 
0155 static struct nasgpio_led *get_led_named(char *name)
0156 {
0157     int i;
0158     for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
0159         if (strcmp(nasgpio_leds[i].name, name))
0160             continue;
0161         return &nasgpio_leds[i];
0162     }
0163     return NULL;
0164 }
0165 
0166 /*
0167  * This protects access to the gpio ports.
0168  */
0169 static DEFINE_SPINLOCK(nasgpio_gpio_lock);
0170 
0171 /*
0172  * There are two gpio ports, one for blinking and the other
0173  * for power.  @port tells us if we're doing blinking or
0174  * power control.
0175  *
0176  * Caller must hold nasgpio_gpio_lock
0177  */
0178 static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
0179                    u32 port, u32 value)
0180 {
0181     struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
0182     u32 gpio_out;
0183 
0184     gpio_out = inl(nas_gpio_io_base + port);
0185     if (value)
0186         gpio_out |= (1<<led->gpio_bit);
0187     else
0188         gpio_out &= ~(1<<led->gpio_bit);
0189 
0190     outl(gpio_out, nas_gpio_io_base + port);
0191 }
0192 
0193 static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
0194                  u32 port, u32 value)
0195 {
0196     spin_lock(&nasgpio_gpio_lock);
0197     __nasgpio_led_set_attr(led_cdev, port, value);
0198     spin_unlock(&nasgpio_gpio_lock);
0199 }
0200 
0201 static u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
0202 {
0203     struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
0204     u32 gpio_in;
0205 
0206     spin_lock(&nasgpio_gpio_lock);
0207     gpio_in = inl(nas_gpio_io_base + port);
0208     spin_unlock(&nasgpio_gpio_lock);
0209     if (gpio_in & (1<<led->gpio_bit))
0210         return 1;
0211     return 0;
0212 }
0213 
0214 /*
0215  * There is actual brightness control in the hardware,
0216  * but it is via smbus commands and not implemented
0217  * in this driver.
0218  */
0219 static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
0220                        enum led_brightness brightness)
0221 {
0222     u32 setting = 0;
0223     if (brightness >= LED_HALF)
0224         setting = 1;
0225     /*
0226      * Hold the lock across both operations.  This ensures
0227      * consistency so that both the "turn off blinking"
0228      * and "turn light off" operations complete as a set.
0229      */
0230     spin_lock(&nasgpio_gpio_lock);
0231     /*
0232      * LED class documentation asks that past blink state
0233      * be disabled when brightness is turned to zero.
0234      */
0235     if (brightness == 0)
0236         __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
0237     __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
0238     spin_unlock(&nasgpio_gpio_lock);
0239 }
0240 
0241 static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
0242                  unsigned long *delay_on,
0243                  unsigned long *delay_off)
0244 {
0245     u32 setting = 1;
0246     if (!(*delay_on == 0 && *delay_off == 0) &&
0247         !(*delay_on == 500 && *delay_off == 500))
0248         return -EINVAL;
0249     /*
0250      * These are very approximate.
0251      */
0252     *delay_on = 500;
0253     *delay_off = 500;
0254 
0255     nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
0256 
0257     return 0;
0258 }
0259 
0260 
0261 /*
0262  * Initialize the ICH7 GPIO registers for NAS usage.  The BIOS should have
0263  * already taken care of this, but we will do so in a non destructive manner
0264  * so that we have what we need whether the BIOS did it or not.
0265  */
0266 static int ich7_gpio_init(struct device *dev)
0267 {
0268     int i;
0269     u32 config_data = 0;
0270     u32 all_nas_led = 0;
0271 
0272     for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
0273         all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
0274 
0275     spin_lock(&nasgpio_gpio_lock);
0276     /*
0277      * We need to enable all of the GPIO lines used by the NAS box,
0278      * so we will read the current Use Selection and add our usage
0279      * to it.  This should be benign with regard to the original
0280      * BIOS configuration.
0281      */
0282     config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
0283     dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
0284     config_data |= all_nas_led + NAS_RECOVERY;
0285     outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
0286     config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
0287     dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
0288 
0289     /*
0290      * The LED GPIO outputs need to be configured for output, so we
0291      * will ensure that all LED lines are cleared for output and the
0292      * RECOVERY line ready for input.  This too should be benign with
0293      * regard to BIOS configuration.
0294      */
0295     config_data = inl(nas_gpio_io_base + GP_IO_SEL);
0296     dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
0297                     config_data);
0298     config_data &= ~all_nas_led;
0299     config_data |= NAS_RECOVERY;
0300     outl(config_data, nas_gpio_io_base + GP_IO_SEL);
0301     config_data = inl(nas_gpio_io_base + GP_IO_SEL);
0302     dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
0303 
0304     /*
0305      * In our final system, the BIOS will initialize the state of all
0306      * of the LEDs.  For now, we turn them all off (or Low).
0307      */
0308     config_data = inl(nas_gpio_io_base + GP_LVL);
0309     dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
0310     /*
0311      * In our final system, the BIOS will initialize the blink state of all
0312      * of the LEDs.  For now, we turn blink off for all of them.
0313      */
0314     config_data = inl(nas_gpio_io_base + GPO_BLINK);
0315     dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
0316 
0317     /*
0318      * At this moment, I am unsure if anything needs to happen with GPI_INV
0319      */
0320     config_data = inl(nas_gpio_io_base + GPI_INV);
0321     dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
0322 
0323     spin_unlock(&nasgpio_gpio_lock);
0324     return 0;
0325 }
0326 
0327 static void ich7_lpc_cleanup(struct device *dev)
0328 {
0329     /*
0330      * If we were given exclusive use of the GPIO
0331      * I/O Address range, we must return it.
0332      */
0333     if (gp_gpio_resource) {
0334         dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
0335         release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
0336         gp_gpio_resource = NULL;
0337     }
0338 }
0339 
0340 /*
0341  * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
0342  * so we can retrive the required operational information and prepare the GPIO.
0343  */
0344 static struct pci_dev *nas_gpio_pci_dev;
0345 static int ich7_lpc_probe(struct pci_dev *dev,
0346                     const struct pci_device_id *id)
0347 {
0348     int status;
0349     u32 gc = 0;
0350 
0351     status = pci_enable_device(dev);
0352     if (status) {
0353         dev_err(&dev->dev, "pci_enable_device failed\n");
0354         return -EIO;
0355     }
0356 
0357     nas_gpio_pci_dev = dev;
0358     status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
0359     if (status)
0360         goto out;
0361     g_pm_io_base &= 0x00000ff80;
0362 
0363     status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
0364     if (!(GPIO_EN & gc)) {
0365         status = -EEXIST;
0366         dev_info(&dev->dev,
0367                "ERROR: The LPC GPIO Block has not been enabled.\n");
0368         goto out;
0369     }
0370 
0371     status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
0372     if (0 > status) {
0373         dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
0374         goto out;
0375     }
0376     dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
0377     nas_gpio_io_base &= 0x00000ffc0;
0378 
0379     /*
0380      * Insure that we have exclusive access to the GPIO I/O address range.
0381      */
0382     gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
0383                       KBUILD_MODNAME);
0384     if (NULL == gp_gpio_resource) {
0385         dev_info(&dev->dev,
0386              "ERROR Unable to register GPIO I/O addresses.\n");
0387         status = -1;
0388         goto out;
0389     }
0390 
0391     /*
0392      * Initialize the GPIO for NAS/Home Server Use
0393      */
0394     ich7_gpio_init(&dev->dev);
0395 
0396 out:
0397     if (status) {
0398         ich7_lpc_cleanup(&dev->dev);
0399         pci_disable_device(dev);
0400     }
0401     return status;
0402 }
0403 
0404 static void ich7_lpc_remove(struct pci_dev *dev)
0405 {
0406     ich7_lpc_cleanup(&dev->dev);
0407     pci_disable_device(dev);
0408 }
0409 
0410 /*
0411  * pci_driver structure passed to the PCI modules
0412  */
0413 static struct pci_driver nas_gpio_pci_driver = {
0414     .name = KBUILD_MODNAME,
0415     .id_table = ich7_lpc_pci_id,
0416     .probe = ich7_lpc_probe,
0417     .remove = ich7_lpc_remove,
0418 };
0419 
0420 static struct led_classdev *get_classdev_for_led_nr(int nr)
0421 {
0422     struct nasgpio_led *nas_led = &nasgpio_leds[nr];
0423     struct led_classdev *led = &nas_led->led_cdev;
0424     return led;
0425 }
0426 
0427 
0428 static void set_power_light_amber_noblink(void)
0429 {
0430     struct nasgpio_led *amber = get_led_named("power:amber:power");
0431     struct nasgpio_led *blue = get_led_named("power:blue:power");
0432 
0433     if (!amber || !blue)
0434         return;
0435     /*
0436      * LED_OFF implies disabling future blinking
0437      */
0438     pr_debug("setting blue off and amber on\n");
0439 
0440     nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
0441     nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
0442 }
0443 
0444 static ssize_t blink_show(struct device *dev,
0445               struct device_attribute *attr, char *buf)
0446 {
0447     struct led_classdev *led = dev_get_drvdata(dev);
0448     int blinking = 0;
0449     if (nasgpio_led_get_attr(led, GPO_BLINK))
0450         blinking = 1;
0451     return sprintf(buf, "%u\n", blinking);
0452 }
0453 
0454 static ssize_t blink_store(struct device *dev,
0455                struct device_attribute *attr,
0456                const char *buf, size_t size)
0457 {
0458     int ret;
0459     struct led_classdev *led = dev_get_drvdata(dev);
0460     unsigned long blink_state;
0461 
0462     ret = kstrtoul(buf, 10, &blink_state);
0463     if (ret)
0464         return ret;
0465 
0466     nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
0467 
0468     return size;
0469 }
0470 
0471 static DEVICE_ATTR_RW(blink);
0472 
0473 static struct attribute *nasgpio_led_attrs[] = {
0474     &dev_attr_blink.attr,
0475     NULL
0476 };
0477 ATTRIBUTE_GROUPS(nasgpio_led);
0478 
0479 static int register_nasgpio_led(int led_nr)
0480 {
0481     struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
0482     struct led_classdev *led = get_classdev_for_led_nr(led_nr);
0483 
0484     led->name = nas_led->name;
0485     led->brightness = LED_OFF;
0486     if (nasgpio_led_get_attr(led, GP_LVL))
0487         led->brightness = LED_FULL;
0488     led->brightness_set = nasgpio_led_set_brightness;
0489     led->blink_set = nasgpio_led_set_blink;
0490     led->groups = nasgpio_led_groups;
0491 
0492     return led_classdev_register(&nas_gpio_pci_dev->dev, led);
0493 }
0494 
0495 static void unregister_nasgpio_led(int led_nr)
0496 {
0497     struct led_classdev *led = get_classdev_for_led_nr(led_nr);
0498     led_classdev_unregister(led);
0499 }
0500 /*
0501  * module load/initialization
0502  */
0503 static int __init nas_gpio_init(void)
0504 {
0505     int i;
0506     int ret = 0;
0507     int nr_devices = 0;
0508 
0509     nr_devices = dmi_check_system(nas_led_whitelist);
0510     if (nodetect) {
0511         pr_info("skipping hardware autodetection\n");
0512         pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
0513         nr_devices++;
0514     }
0515 
0516     if (nr_devices <= 0) {
0517         pr_info("no LED devices found\n");
0518         return -ENODEV;
0519     }
0520 
0521     pr_info("registering PCI driver\n");
0522     ret = pci_register_driver(&nas_gpio_pci_driver);
0523     if (ret)
0524         return ret;
0525     for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
0526         ret = register_nasgpio_led(i);
0527         if (ret)
0528             goto out_err;
0529     }
0530     /*
0531      * When the system powers on, the BIOS leaves the power
0532      * light blue and blinking.  This will turn it solid
0533      * amber once the driver is loaded.
0534      */
0535     set_power_light_amber_noblink();
0536     return 0;
0537 out_err:
0538     for (i--; i >= 0; i--)
0539         unregister_nasgpio_led(i);
0540     pci_unregister_driver(&nas_gpio_pci_driver);
0541     return ret;
0542 }
0543 
0544 /*
0545  * module unload
0546  */
0547 static void __exit nas_gpio_exit(void)
0548 {
0549     int i;
0550     pr_info("Unregistering driver\n");
0551     for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
0552         unregister_nasgpio_led(i);
0553     pci_unregister_driver(&nas_gpio_pci_driver);
0554 }
0555 
0556 module_init(nas_gpio_init);
0557 module_exit(nas_gpio_exit);