root/drivers/char/ipmi/kcs_bmc_aspeed.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. aspeed_kcs_inb
  2. aspeed_kcs_outb
  3. aspeed_kcs_set_address
  4. aspeed_kcs_enable_channel
  5. aspeed_kcs_irq
  6. aspeed_kcs_config_irq
  7. aspeed_kcs_probe
  8. aspeed_kcs_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2015-2018, Intel Corporation.
   4  */
   5 
   6 #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
   7 
   8 #include <linux/atomic.h>
   9 #include <linux/errno.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/io.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/module.h>
  14 #include <linux/of.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/poll.h>
  17 #include <linux/regmap.h>
  18 #include <linux/sched.h>
  19 #include <linux/slab.h>
  20 #include <linux/timer.h>
  21 
  22 #include "kcs_bmc.h"
  23 
  24 
  25 #define DEVICE_NAME     "ast-kcs-bmc"
  26 
  27 #define KCS_CHANNEL_MAX     4
  28 
  29 /* mapped to lpc-bmc@0 IO space */
  30 #define LPC_HICR0            0x000
  31 #define     LPC_HICR0_LPC3E          BIT(7)
  32 #define     LPC_HICR0_LPC2E          BIT(6)
  33 #define     LPC_HICR0_LPC1E          BIT(5)
  34 #define LPC_HICR2            0x008
  35 #define     LPC_HICR2_IBFIF3         BIT(3)
  36 #define     LPC_HICR2_IBFIF2         BIT(2)
  37 #define     LPC_HICR2_IBFIF1         BIT(1)
  38 #define LPC_HICR4            0x010
  39 #define     LPC_HICR4_LADR12AS       BIT(7)
  40 #define     LPC_HICR4_KCSENBL        BIT(2)
  41 #define LPC_LADR3H           0x014
  42 #define LPC_LADR3L           0x018
  43 #define LPC_LADR12H          0x01C
  44 #define LPC_LADR12L          0x020
  45 #define LPC_IDR1             0x024
  46 #define LPC_IDR2             0x028
  47 #define LPC_IDR3             0x02C
  48 #define LPC_ODR1             0x030
  49 #define LPC_ODR2             0x034
  50 #define LPC_ODR3             0x038
  51 #define LPC_STR1             0x03C
  52 #define LPC_STR2             0x040
  53 #define LPC_STR3             0x044
  54 
  55 /* mapped to lpc-host@80 IO space */
  56 #define LPC_HICRB            0x080
  57 #define     LPC_HICRB_IBFIF4         BIT(1)
  58 #define     LPC_HICRB_LPC4E          BIT(0)
  59 #define LPC_LADR4            0x090
  60 #define LPC_IDR4             0x094
  61 #define LPC_ODR4             0x098
  62 #define LPC_STR4             0x09C
  63 
  64 struct aspeed_kcs_bmc {
  65         struct regmap *map;
  66 };
  67 
  68 
  69 static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
  70 {
  71         struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
  72         u32 val = 0;
  73         int rc;
  74 
  75         rc = regmap_read(priv->map, reg, &val);
  76         WARN(rc != 0, "regmap_read() failed: %d\n", rc);
  77 
  78         return rc == 0 ? (u8) val : 0;
  79 }
  80 
  81 static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
  82 {
  83         struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
  84         int rc;
  85 
  86         rc = regmap_write(priv->map, reg, data);
  87         WARN(rc != 0, "regmap_write() failed: %d\n", rc);
  88 }
  89 
  90 
  91 /*
  92  * AST_usrGuide_KCS.pdf
  93  * 2. Background:
  94  *   we note D for Data, and C for Cmd/Status, default rules are
  95  *     A. KCS1 / KCS2 ( D / C:X / X+4 )
  96  *        D / C : CA0h / CA4h
  97  *        D / C : CA8h / CACh
  98  *     B. KCS3 ( D / C:XX2h / XX3h )
  99  *        D / C : CA2h / CA3h
 100  *        D / C : CB2h / CB3h
 101  *     C. KCS4
 102  *        D / C : CA4h / CA5h
 103  */
 104 static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
 105 {
 106         struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
 107 
 108         switch (kcs_bmc->channel) {
 109         case 1:
 110                 regmap_update_bits(priv->map, LPC_HICR4,
 111                                 LPC_HICR4_LADR12AS, 0);
 112                 regmap_write(priv->map, LPC_LADR12H, addr >> 8);
 113                 regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
 114                 break;
 115 
 116         case 2:
 117                 regmap_update_bits(priv->map, LPC_HICR4,
 118                                 LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
 119                 regmap_write(priv->map, LPC_LADR12H, addr >> 8);
 120                 regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
 121                 break;
 122 
 123         case 3:
 124                 regmap_write(priv->map, LPC_LADR3H, addr >> 8);
 125                 regmap_write(priv->map, LPC_LADR3L, addr & 0xFF);
 126                 break;
 127 
 128         case 4:
 129                 regmap_write(priv->map, LPC_LADR4, ((addr + 1) << 16) |
 130                         addr);
 131                 break;
 132 
 133         default:
 134                 break;
 135         }
 136 }
 137 
 138 static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
 139 {
 140         struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
 141 
 142         switch (kcs_bmc->channel) {
 143         case 1:
 144                 if (enable) {
 145                         regmap_update_bits(priv->map, LPC_HICR2,
 146                                         LPC_HICR2_IBFIF1, LPC_HICR2_IBFIF1);
 147                         regmap_update_bits(priv->map, LPC_HICR0,
 148                                         LPC_HICR0_LPC1E, LPC_HICR0_LPC1E);
 149                 } else {
 150                         regmap_update_bits(priv->map, LPC_HICR0,
 151                                         LPC_HICR0_LPC1E, 0);
 152                         regmap_update_bits(priv->map, LPC_HICR2,
 153                                         LPC_HICR2_IBFIF1, 0);
 154                 }
 155                 break;
 156 
 157         case 2:
 158                 if (enable) {
 159                         regmap_update_bits(priv->map, LPC_HICR2,
 160                                         LPC_HICR2_IBFIF2, LPC_HICR2_IBFIF2);
 161                         regmap_update_bits(priv->map, LPC_HICR0,
 162                                         LPC_HICR0_LPC2E, LPC_HICR0_LPC2E);
 163                 } else {
 164                         regmap_update_bits(priv->map, LPC_HICR0,
 165                                         LPC_HICR0_LPC2E, 0);
 166                         regmap_update_bits(priv->map, LPC_HICR2,
 167                                         LPC_HICR2_IBFIF2, 0);
 168                 }
 169                 break;
 170 
 171         case 3:
 172                 if (enable) {
 173                         regmap_update_bits(priv->map, LPC_HICR2,
 174                                         LPC_HICR2_IBFIF3, LPC_HICR2_IBFIF3);
 175                         regmap_update_bits(priv->map, LPC_HICR0,
 176                                         LPC_HICR0_LPC3E, LPC_HICR0_LPC3E);
 177                         regmap_update_bits(priv->map, LPC_HICR4,
 178                                         LPC_HICR4_KCSENBL, LPC_HICR4_KCSENBL);
 179                 } else {
 180                         regmap_update_bits(priv->map, LPC_HICR0,
 181                                         LPC_HICR0_LPC3E, 0);
 182                         regmap_update_bits(priv->map, LPC_HICR4,
 183                                         LPC_HICR4_KCSENBL, 0);
 184                         regmap_update_bits(priv->map, LPC_HICR2,
 185                                         LPC_HICR2_IBFIF3, 0);
 186                 }
 187                 break;
 188 
 189         case 4:
 190                 if (enable)
 191                         regmap_update_bits(priv->map, LPC_HICRB,
 192                                         LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
 193                                         LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E);
 194                 else
 195                         regmap_update_bits(priv->map, LPC_HICRB,
 196                                         LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
 197                                         0);
 198                 break;
 199 
 200         default:
 201                 break;
 202         }
 203 }
 204 
 205 static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
 206 {
 207         struct kcs_bmc *kcs_bmc = arg;
 208 
 209         if (!kcs_bmc_handle_event(kcs_bmc))
 210                 return IRQ_HANDLED;
 211 
 212         return IRQ_NONE;
 213 }
 214 
 215 static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
 216                         struct platform_device *pdev)
 217 {
 218         struct device *dev = &pdev->dev;
 219         int irq;
 220 
 221         irq = platform_get_irq(pdev, 0);
 222         if (irq < 0)
 223                 return irq;
 224 
 225         return devm_request_irq(dev, irq, aspeed_kcs_irq, IRQF_SHARED,
 226                                 dev_name(dev), kcs_bmc);
 227 }
 228 
 229 static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
 230         { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 },
 231         { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 },
 232         { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 },
 233         { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
 234 };
 235 
 236 static int aspeed_kcs_probe(struct platform_device *pdev)
 237 {
 238         struct device *dev = &pdev->dev;
 239         struct aspeed_kcs_bmc *priv;
 240         struct kcs_bmc *kcs_bmc;
 241         u32 chan, addr;
 242         int rc;
 243 
 244         rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
 245         if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
 246                 dev_err(dev, "no valid 'kcs_chan' configured\n");
 247                 return -ENODEV;
 248         }
 249 
 250         rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
 251         if (rc) {
 252                 dev_err(dev, "no valid 'kcs_addr' configured\n");
 253                 return -ENODEV;
 254         }
 255 
 256         kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
 257         if (!kcs_bmc)
 258                 return -ENOMEM;
 259 
 260         priv = kcs_bmc_priv(kcs_bmc);
 261         priv->map = syscon_node_to_regmap(dev->parent->of_node);
 262         if (IS_ERR(priv->map)) {
 263                 dev_err(dev, "Couldn't get regmap\n");
 264                 return -ENODEV;
 265         }
 266 
 267         kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
 268         kcs_bmc->io_inputb = aspeed_kcs_inb;
 269         kcs_bmc->io_outputb = aspeed_kcs_outb;
 270 
 271         dev_set_drvdata(dev, kcs_bmc);
 272 
 273         aspeed_kcs_set_address(kcs_bmc, addr);
 274         aspeed_kcs_enable_channel(kcs_bmc, true);
 275         rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
 276         if (rc)
 277                 return rc;
 278 
 279         rc = misc_register(&kcs_bmc->miscdev);
 280         if (rc) {
 281                 dev_err(dev, "Unable to register device\n");
 282                 return rc;
 283         }
 284 
 285         pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
 286                 chan, addr,
 287                 kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
 288 
 289         return 0;
 290 }
 291 
 292 static int aspeed_kcs_remove(struct platform_device *pdev)
 293 {
 294         struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
 295 
 296         misc_deregister(&kcs_bmc->miscdev);
 297 
 298         return 0;
 299 }
 300 
 301 static const struct of_device_id ast_kcs_bmc_match[] = {
 302         { .compatible = "aspeed,ast2400-kcs-bmc" },
 303         { .compatible = "aspeed,ast2500-kcs-bmc" },
 304         { }
 305 };
 306 MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
 307 
 308 static struct platform_driver ast_kcs_bmc_driver = {
 309         .driver = {
 310                 .name           = DEVICE_NAME,
 311                 .of_match_table = ast_kcs_bmc_match,
 312         },
 313         .probe  = aspeed_kcs_probe,
 314         .remove = aspeed_kcs_remove,
 315 };
 316 module_platform_driver(ast_kcs_bmc_driver);
 317 
 318 MODULE_LICENSE("GPL v2");
 319 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
 320 MODULE_DESCRIPTION("Aspeed device interface to the KCS BMC device");

/* [<][>][^][v][top][bottom][index][help] */