1. drivers/rtc: Add rtc-astbmc module.

2. drivers/char/ipmi: Initialize ipmi_si module using hardcode method.
3. Rtc-astbmc module is initialized before ipmi_si module.
This commit is contained in:
zhaohui-yan 2023-12-25 17:27:13 +08:00 committed by Xiaoguang Xing
parent c625b83f55
commit 926e0793f6
7 changed files with 634 additions and 8 deletions

View File

@ -1605,8 +1605,9 @@ CONFIG_RPMSG_TTY=m
CONFIG_SERIAL_DEV_BUS=y
CONFIG_TTY_PRINTK=m
CONFIG_VIRTIO_CONSOLE=m
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_HANDLER=y
CONFIG_IPMI_DEVICE_INTERFACE=y
CONFIG_IPMI_SI=y
CONFIG_IPMI_SSIF=m
CONFIG_IPMI_IPMB=m
CONFIG_IPMI_WATCHDOG=m
@ -2940,6 +2941,7 @@ CONFIG_RTC_DRV_BQ4802=m
CONFIG_RTC_DRV_RP5C01=m
CONFIG_RTC_DRV_V3020=m
CONFIG_RTC_DRV_R7301=m
CONFIG_RTC_DRV_ASTBMC=y
CONFIG_DMADEVICES=y
CONFIG_ALTERA_MSGDMA=m
CONFIG_DW_DMAC=m

View File

@ -2000,9 +2000,9 @@ CONFIG_TTY_PRINTK=y
CONFIG_PRINTER=m
CONFIG_PPDEV=m
CONFIG_VIRTIO_CONSOLE=y
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_IPMI_HANDLER=y
CONFIG_IPMI_DEVICE_INTERFACE=y
CONFIG_IPMI_SI=y
CONFIG_IPMI_SSIF=m
CONFIG_IPMI_WATCHDOG=m
CONFIG_IPMI_POWEROFF=m
@ -4046,6 +4046,7 @@ CONFIG_RTC_DRV_MT6397=m
CONFIG_RTC_DRV_R7301=m
CONFIG_RTC_DRV_CPCAP=m
CONFIG_RTC_DRV_HID_SENSOR_TIME=m
CONFIG_RTC_DRV_ASTBMC=m
CONFIG_DMADEVICES=y
CONFIG_ALTERA_MSGDMA=m
CONFIG_DW_AXI_DMAC=m

View File

@ -6,7 +6,7 @@
#include <linux/platform_device.h>
#include "ipmi_si.h"
#include "ipmi_plat_data.h"
#include <linux/pci.h>
/*
* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
* a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS.
@ -90,6 +90,24 @@ static void __init ipmi_hardcode_init_one(const char *si_type_str,
ipmi_platform_add("hardcode-ipmi-si", i, &p);
}
#ifdef CONFIG_ARCH_SOPHGO
static void variable_init(struct pci_dev *pdev)
{
unsigned long addr_data = pci_resource_start(pdev, 1) + 0x0e80;
// printk("addr_data=0x%lx\n", addr_data);
strcpy(si_type_str, "kcs");
addrs[0] = addr_data;
num_addrs = 1;
regspacings[0] = 4;
num_regspacings = 1;
regsizes[0] = 4;
num_regsizes = 1;
irqs[0] = 0;
num_irqs = 1;
slave_addrs[0] = 0;
num_slave_addrs = 1;
}
#endif
void __init ipmi_hardcode_init(void)
{
unsigned int i;
@ -97,7 +115,11 @@ void __init ipmi_hardcode_init(void)
char *si_type[SI_MAX_PARMS];
memset(si_type, 0, sizeof(si_type));
#ifdef CONFIG_ARCH_SOPHGO
struct pci_dev *pdev = pci_get_device(0x1A03, 0x2402, NULL);
if (pdev != NULL)
variable_init(pdev);
#endif
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {

View File

@ -2156,7 +2156,8 @@ skip_fallback_noirq:
return 0;
}
}
module_init(init_ipmi_si);
// module_init(init_ipmi_si);
late_initcall(init_ipmi_si);
static void wait_msg_processed(struct smi_info *smi_info)
{

View File

@ -1995,4 +1995,10 @@ config RTC_DRV_POLARFIRE_SOC
This driver can also be built as a module, if so, the module
will be called "rtc-mpfs".
config RTC_DRV_ASTBMC
tristate "SG2042 server get rtc time from bmc via pci bus"
help
This driver can also be built as a module, if so, the module
will be called "rtc-astbmc".
endif # RTC_CLASS

View File

@ -186,3 +186,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o
obj-$(CONFIG_RTC_DRV_ASTBMC) += rtc-astbmc.o

593
drivers/rtc/rtc-astbmc.c Normal file
View File

@ -0,0 +1,593 @@
// SPDX-License-Identifier: GPL-2.0-only
/* rtc-astbmc.c
*
* Driver for Dallas Semiconductor astbmcrtc Low Current, PCI Compatible
* Real Time Clock
*
* Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
#include <linux/regmap.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/miscdevice.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
/* Registers in astbmcrtc rtc */
#define ASPEED_PCI_BMC_HOST2BMC_Q1 0x30000
#define ASPEED_PCI_BMC_HOST2BMC_Q2 0x30010
#define ASPEED_PCI_BMC_BMC2HOST_Q1 0x30020
#define ASPEED_PCI_BMC_BMC2HOST_Q2 0x30030
#define ASPEED_PCI_BMC_BMC2HOST_STS 0x30040
#define BMC2HOST_INT_STS_DOORBELL BIT(31)
#define BMC2HOST_ENABLE_INTB BIT(30)
/* */
#define BMC2HOST_Q1_FULL BIT(27)
#define BMC2HOST_Q1_EMPTY BIT(26)
#define BMC2HOST_Q2_FULL BIT(25)
#define BMC2HOST_Q2_EMPTY BIT(24)
#define BMC2HOST_Q1_FULL_UNMASK BIT(23)
#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22)
#define BMC2HOST_Q2_FULL_UNMASK BIT(21)
#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20)
#define ASPEED_PCI_BMC_HOST2BMC_STS 0x30044
#define HOST2BMC_INT_STS_DOORBELL BIT(31)
#define HOST2BMC_ENABLE_INTB BIT(30)
/* */
#define HOST2BMC_Q1_FULL BIT(27)
#define HOST2BMC_Q1_EMPTY BIT(26)
#define HOST2BMC_Q2_FULL BIT(25)
#define HOST2BMC_Q2_EMPTY BIT(24)
#define HOST2BMC_Q1_FULL_UNMASK BIT(23)
#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22)
#define HOST2BMC_Q2_FULL_UNMASK BIT(21)
#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20)
struct aspeed_pci_bmc_dev {
struct device *dev;
struct miscdevice miscdev;
unsigned long mem_bar_base;
unsigned long mem_bar_size;
void __iomem *mem_bar_reg;
unsigned long message_bar_base;
unsigned long message_bar_size;
void __iomem *msg_bar_reg;
struct bin_attribute bin0;
struct bin_attribute bin1;
struct kernfs_node *kn0;
struct kernfs_node *kn1;
/* Queue waiters for idle engine */
wait_queue_head_t tx_wait0;
wait_queue_head_t tx_wait1;
wait_queue_head_t rx_wait0;
wait_queue_head_t rx_wait1;
void __iomem *sio_mbox_reg;
int sio_mbox_irq;
u8 IntLine;
int legency_irq;
};
#define HOST_BMC_QUEUE_SIZE (16 * 4)
#define PCIE_DEVICE_SIO_ADDR (0x2E * 4)
#define BMC_MULTI_MSI 32
#define DRIVER_NAME "ASPEED BMC DEVICE"
#define VUART_MAX_PARMS 2
static uint16_t vuart_ioport[VUART_MAX_PARMS];
static uint16_t vuart_sirq[VUART_MAX_PARMS];
static struct rtc_device *rtc;
static int time64_flag = 1;
module_param(time64_flag, int, 0644);
static struct aspeed_pci_bmc_dev *file_aspeed_bmc_device(struct file *file)
{
return container_of(file->private_data, struct aspeed_pci_bmc_dev,
miscdev);
}
static int aspeed_pci_bmc_dev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct aspeed_pci_bmc_dev *pci_bmc_dev = file_aspeed_bmc_device(file);
unsigned long vsize = vma->vm_end - vma->vm_start;
pgprot_t prot = vma->vm_page_prot;
if (vma->vm_pgoff + vsize > pci_bmc_dev->mem_bar_base + 0x100000)
return -EINVAL;
prot = pgprot_noncached(prot);
if (remap_pfn_range(vma, vma->vm_start,
(pci_bmc_dev->mem_bar_base >> PAGE_SHIFT) + vma->vm_pgoff,
vsize, prot))
return -EAGAIN;
return 0;
}
static const struct file_operations aspeed_pci_bmc_dev_fops = {
.owner = THIS_MODULE,
.mmap = aspeed_pci_bmc_dev_mmap,
};
static irqreturn_t aspeed_pci_host_bmc_device_interrupt(int irq, void *dev_id)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id;
u32 bmc2host_q_sts = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
if (bmc2host_q_sts & BMC2HOST_INT_STS_DOORBELL)
writel(BMC2HOST_INT_STS_DOORBELL, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
if (bmc2host_q_sts & BMC2HOST_ENABLE_INTB)
writel(BMC2HOST_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
if (bmc2host_q_sts & BMC2HOST_Q1_FULL)
dev_info(pci_bmc_device->dev, "Q1 Full\n");
if (bmc2host_q_sts & BMC2HOST_Q2_FULL)
dev_info(pci_bmc_device->dev, "Q2 Full\n");
//check q1
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL))
wake_up_interruptible(&pci_bmc_device->tx_wait0);
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY))
wake_up_interruptible(&pci_bmc_device->rx_wait0);
//chech q2
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL))
wake_up_interruptible(&pci_bmc_device->tx_wait1);
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY))
wake_up_interruptible(&pci_bmc_device->rx_wait1);
return IRQ_HANDLED;
}
static irqreturn_t aspeed_pci_host_mbox_interrupt(int irq, void *dev_id)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id;
u32 isr = readl(pci_bmc_device->sio_mbox_reg + 0x94);
if (isr & BIT(7))
writel(BIT(7), pci_bmc_device->sio_mbox_reg + 0x94);
return IRQ_HANDLED;
}
static void clear_r_queue1(struct device *dev)
{
u32 value;
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
while (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) {
value = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
}
}
static ssize_t read_8bytes_from_queue1(struct device *dev, time64_t * time_stamp)
{
int i = 0;
u32 * time_buf = (u32*)time_stamp;
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
while(i < 2) {
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) {
time_buf[i++] = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
}
}
return sizeof(time64_t);
}
static ssize_t read_queue1(struct device *dev, u32 * data)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
int ret;
ret = wait_event_interruptible(pci_bmc_device->rx_wait0,
!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY));
if (ret)
return -EINTR;
* data = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
return sizeof(u32);
}
static ssize_t write_queue1(struct device *dev, u32 data)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
int ret;
ret = wait_event_interruptible(pci_bmc_device->tx_wait0,
!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL));
if (ret)
return -EINTR;
writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q1);
//trigger to host
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
return sizeof(u32);
}
static ssize_t read_queue2(struct device *dev, u32 * timestamp)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
int ret;
ret = wait_event_interruptible(pci_bmc_device->rx_wait1,
!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY));
if (ret)
return -EINTR;
* timestamp = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q2);
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
return sizeof(u32);
}
static ssize_t write_queue2(struct device *dev, u32 data)
{
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
int ret;
ret = wait_event_interruptible(pci_bmc_device->tx_wait1,
!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL));
if (ret)
return -EINTR;
writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2);
//trigger to host
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
return sizeof(u32);
}
static ssize_t write_8bytes_to_queue2(struct device *dev, time64_t * time_stamp)
{
int i = 0;
u32 * time_buf = (u32*)time_stamp;
struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
while(i < 2) {
if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) {
writel(time_buf[i++], pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2);
writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
}
}
return sizeof(time64_t);
}
static int astbmc_read_time(struct device *dev, struct rtc_time *dt)
{
time64_t time_stamp = 0;
u32 tx_cmd = 0x55555555;
clear_r_queue1(dev);
write_queue1(dev, tx_cmd);
if (time64_flag) {
read_8bytes_from_queue1(dev, &time_stamp);
} else {
read_queue1(dev,(u32*)&time_stamp);
}
// printk("r-t:0x%lx",time_stamp);
rtc_time64_to_tm(time_stamp, dt);
return 0;
}
static int astbmc_set_time(struct device *dev, struct rtc_time *dt)
{
time64_t time_stamp = 0;
u32 tx_cmd = 0xaaaaaaaa;
write_queue2(dev, tx_cmd);
time_stamp = rtc_tm_to_time64(dt);
// printk("s-t:0x%lx",time_stamp);
if (time64_flag) {
write_8bytes_to_queue2(dev, &time_stamp);
} else {
write_queue2(dev, (u32)time_stamp);
}
return 0;
}
static const struct rtc_class_ops astbmc_rtc_ops = {
.read_time = astbmc_read_time,
.set_time = astbmc_set_time,
};
#define BMC_MSI_IDX_BASE 0
static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct uart_8250_port uart[VUART_MAX_PARMS];
struct aspeed_pci_bmc_dev *pci_bmc_dev;
struct device *dev = &pdev->dev;
void __iomem *pcie_sio_decode_addr;
u16 config_cmd_val;
int nr_entries;
unsigned long irqflags;
int rc = 0;
int i = 0;
pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);
pci_bmc_dev = kzalloc(sizeof(*pci_bmc_dev), GFP_KERNEL);
if (!pci_bmc_dev) {
rc = -ENOMEM;
dev_err(&pdev->dev, "kmalloc() returned NULL memory.\n");
goto out_err;
}
rc = pci_enable_device(pdev);
if (rc != 0) {
dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
goto out_err;
}
/* set PCI host mastering */
pci_set_master(pdev);
nr_entries = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
if (nr_entries < 0) {
pci_bmc_dev->legency_irq = 1;
pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val);
config_cmd_val &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val);
} else {
pci_bmc_dev->legency_irq = 0;
pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val);
config_cmd_val |= PCI_COMMAND_INTX_DISABLE;
pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val);
pdev->irq = pci_irq_vector(pdev, BMC_MSI_IDX_BASE);
}
pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);
init_waitqueue_head(&pci_bmc_dev->tx_wait0);
init_waitqueue_head(&pci_bmc_dev->tx_wait1);
init_waitqueue_head(&pci_bmc_dev->rx_wait0);
init_waitqueue_head(&pci_bmc_dev->rx_wait1);
//Get MEM bar
pci_bmc_dev->mem_bar_base = pci_resource_start(pdev, 0);
pci_bmc_dev->mem_bar_size = pci_resource_len(pdev, 0);
pr_info("BAR0 I/O Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->mem_bar_base, pci_bmc_dev->mem_bar_size);
pci_bmc_dev->mem_bar_reg = pci_ioremap_bar(pdev, 0);
if (!pci_bmc_dev->mem_bar_reg) {
rc = -ENOMEM;
goto out_free0;
}
//Get MSG BAR info
pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
pr_info("MSG BAR1 Memory Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->message_bar_base, pci_bmc_dev->message_bar_size);
pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
if (!pci_bmc_dev->msg_bar_reg) {
rc = -ENOMEM;
goto out_free1;
}
/* ERRTA40: dummy read */
(void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
pci_bmc_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
pci_bmc_dev->miscdev.name = DRIVER_NAME;
pci_bmc_dev->miscdev.fops = &aspeed_pci_bmc_dev_fops;
pci_bmc_dev->miscdev.parent = dev;
rc = misc_register(&pci_bmc_dev->miscdev);
if (rc) {
pr_err("host bmc register fail %d\n", rc);
goto out_free;
}
pci_set_drvdata(pdev, pci_bmc_dev);
// irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
rc = request_irq(pdev->irq, aspeed_pci_host_bmc_device_interrupt, IRQF_SHARED, "ASPEED BMC DEVICE", pci_bmc_dev);
if (rc) {
pr_err("host bmc device Unable to get IRQ %d\n", rc);
goto out_unreg;
}
#if 1
/* setup mbox */
pcie_sio_decode_addr = pci_bmc_dev->msg_bar_reg + PCIE_DEVICE_SIO_ADDR;
writel(0xaa, pcie_sio_decode_addr);
writel(0xa5, pcie_sio_decode_addr);
writel(0xa5, pcie_sio_decode_addr);
writel(0x07, pcie_sio_decode_addr);
writel(0x0e, pcie_sio_decode_addr + 0x04);
/* disable */
writel(0x30, pcie_sio_decode_addr);
writel(0x00, pcie_sio_decode_addr + 0x04);
/* set decode address 0x100 */
writel(0x60, pcie_sio_decode_addr);
writel(0x01, pcie_sio_decode_addr + 0x04);
writel(0x61, pcie_sio_decode_addr);
writel(0x00, pcie_sio_decode_addr + 0x04);
/* enable */
writel(0x30, pcie_sio_decode_addr);
writel(0x01, pcie_sio_decode_addr + 0x04);
pci_bmc_dev->sio_mbox_reg = pci_bmc_dev->msg_bar_reg + 0x400;
if (pci_bmc_dev->legency_irq)
pci_bmc_dev->sio_mbox_irq = pdev->irq;
else
// pci_bmc_dev->sio_mbox_irq = pci_irq_vector(pdev, 0x10 + 9 - BMC_MSI_IDX_BASE);
pci_bmc_dev->sio_mbox_irq = pci_irq_vector(pdev, 0);
rc = request_irq(pci_bmc_dev->sio_mbox_irq, aspeed_pci_host_mbox_interrupt, IRQF_SHARED, "ASPEED SIO MBOX", pci_bmc_dev);
if (rc)
pr_err("host bmc device Unable to get IRQ %d\n", rc);
/* setup VUART */
memset(uart, 0, sizeof(uart));
for (i = 0; i < VUART_MAX_PARMS; i++) {
vuart_ioport[i] = 0x3F8 - (i * 0x100);
vuart_sirq[i] = 0x10 + 4 - i - BMC_MSI_IDX_BASE;
uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
uart[i].port.uartclk = 115200 * 16;
if (pci_bmc_dev->legency_irq)
uart[i].port.irq = pdev->irq;
else
uart[i].port.irq = pci_irq_vector(pdev, 0);
// uart[i].port.irq = pci_irq_vector(pdev, vuart_sirq[i]);
uart[i].port.dev = &pdev->dev;
uart[i].port.iotype = UPIO_MEM32;
uart[i].port.iobase = 0;
uart[i].port.mapbase = pci_bmc_dev->message_bar_base + (vuart_ioport[i] << 2);
uart[i].port.membase = 0;
uart[i].port.type = PORT_16550A;
uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
uart[i].port.regshift = 2;
rc = serial8250_register_8250_port(&uart[i]);
if (rc < 0) {
dev_err(dev, "cannot setup VUART@%xh over PCIe, rc=%d\n", vuart_ioport[i], rc);
goto out_unreg;
}
}
#endif
//register rtc device
rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
rtc->ops = &astbmc_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
rtc->range_max = RTC_TIMESTAMP_END_9999;
devm_rtc_register_device(rtc);
return 0;
out_unreg:
misc_deregister(&pci_bmc_dev->miscdev);
out_free1:
pci_release_region(pdev, 1);
out_free0:
pci_release_region(pdev, 0);
out_free:
kfree(pci_bmc_dev);
out_err:
pci_disable_device(pdev);
return rc;
}
static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
{
struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
free_irq(pdev->irq, pdev);
misc_deregister(&pci_bmc_dev->miscdev);
pci_release_regions(pdev);
kfree(pci_bmc_dev);
pci_disable_device(pdev);
}
/**
* This table holds the list of (VendorID,DeviceID) supported by this driver
*
*/
static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
{ PCI_DEVICE(0x1A03, 0x2402), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
static struct pci_driver aspeed_host_bmc_dev_driver = {
.name = DRIVER_NAME,
.id_table = aspeed_host_bmc_dev_pci_ids,
.probe = aspeed_pci_host_bmc_device_probe,
.remove = aspeed_pci_host_bmc_device_remove,
};
static int __init aspeed_host_bmc_device_init(void)
{
int ret;
/* register pci driver */
ret = pci_register_driver(&aspeed_host_bmc_dev_driver);
if (ret < 0) {
pr_err("pci-driver: can't register pci driver\n");
return ret;
}
return 0;
}
static void aspeed_host_bmc_device_exit(void)
{
/* unregister pci driver */
pci_unregister_driver(&aspeed_host_bmc_dev_driver);
}
// late_initcall(aspeed_host_bmc_device_init);
module_init(aspeed_host_bmc_device_init);
module_exit(aspeed_host_bmc_device_exit);
MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
MODULE_LICENSE("GPL");