Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/loongarch/configs/deepin_loongarch_desktop_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3622,6 +3622,7 @@ CONFIG_FB_ASILIANT=y
CONFIG_FB_IMSTT=y
CONFIG_FB_UVESA=m
CONFIG_FB_EFI=y
CONFIG_FB_LS2K500=m
CONFIG_FB_OPENCORES=m
CONFIG_FB_S1D13XXX=m
CONFIG_FB_RIVA=m
Expand Down
1 change: 1 addition & 0 deletions arch/loongarch/configs/loongson3_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ CONFIG_DRM_LOONGSON=y
CONFIG_FB=y
CONFIG_FB_EFI=y
CONFIG_FB_RADEON=y
CONFIG_FB_LS2K500=m
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_PLATFORM=m
# CONFIG_VGA_CONSOLE is not set
Expand Down
4 changes: 4 additions & 0 deletions drivers/char/ipmi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ ifdef CONFIG_PARISC
ipmi_si-y += ipmi_si_parisc.o
endif

ifdef CONFIG_LOONGARCH
ipmi_si-y += ipmi_si_ls2k500.o
endif

obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
Expand Down
92 changes: 92 additions & 0 deletions drivers/char/ipmi/btlock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BTLOCK_H__
#define __BTLOCK_H__

#include <linux/delay.h>
#include <asm/timex.h>

union btlock {
char b[2];
unsigned int u;
};

/*
*wait delay us if lock failed.
*lock fail if another one get lock or both try get lock.
*c must compile b with byte access.
*/
static inline int btlock_lock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;
unsigned long c0 = get_cycles(), c1;

if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;

while (1) {
local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
c1 = get_cycles();
if (c1 - c0 > *mscycles * 1000)
return -1;
ndelay(((t.b[1 - n] & 0x7f) + (c1 & 1)) * 100);
}
return 0;
}

static inline int btlock_trylock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;

if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;

local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
ndelay(((t.b[1 - n] & 0x7f) + (get_cycles() & 1)) * 100);
return -1;
}

static inline int btlock_unlock(volatile union btlock *p, int n)
{
p->b[n] = 0;
wmb(); /* flush write out immediately */
return p->u;
}

static inline int btlock_islocked(volatile union btlock *p, int n)
{
union btlock t;

t.u = p->u;
return t.b[n] && !t.b[1 - n];
}
#endif
11 changes: 11 additions & 0 deletions drivers/char/ipmi/ipmi_si.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ struct si_sm_io {
unsigned int regshift;
enum ipmi_addr_space addr_space;
unsigned long addr_data;
#ifdef CONFIG_LOONGARCH
void *addr_source_data;
#endif
enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
union ipmi_smi_info_union addr_info;

Expand Down Expand Up @@ -101,6 +104,14 @@ static inline void ipmi_si_parisc_init(void) { }
static inline void ipmi_si_parisc_shutdown(void) { }
#endif

#ifdef CONFIG_LOONGARCH
int ipmi_si_ls2k500_init(void);
void ipmi_si_ls2k500_shutdown(void);
#else
static inline void ipmi_si_ls2k500_init(void) { }
static inline void ipmi_si_ls2k500_shutdown(void) { }
#endif

int ipmi_si_port_setup(struct si_sm_io *io);
int ipmi_si_mem_setup(struct si_sm_io *io);

Expand Down
4 changes: 4 additions & 0 deletions drivers/char/ipmi/ipmi_si_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2104,6 +2104,8 @@ static int __init init_ipmi_si(void)

ipmi_si_platform_init();

ipmi_si_ls2k500_init();

ipmi_si_pci_init();

ipmi_si_parisc_init();
Expand Down Expand Up @@ -2289,6 +2291,8 @@ static void cleanup_ipmi_si(void)

ipmi_si_parisc_shutdown();

ipmi_si_ls2k500_shutdown();

ipmi_si_platform_shutdown();

mutex_lock(&smi_infos_lock);
Expand Down
173 changes: 173 additions & 0 deletions drivers/char/ipmi/ipmi_si_ls2k500.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ipmi_si_pci.c
*
* Handling for IPMI devices on the PCI bus.
*/

#define pr_fmt(fmt) "ipmi_pci: " fmt

#include <linux/module.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/version.h>
#include "ipmi_si.h"
static unsigned long *mscycles;
static unsigned long *event_jiffies;
#include "kcs_bmc_ls2k500.h"
static int resetbootwait = 60;
module_param(resetbootwait, int, 0664);

#define KCS_STATUS_CMD_DAT BIT(3)

static int pcie_busy(void)
{
if (time_before(jiffies, *event_jiffies + resetbootwait*HZ))
return -1;
return 0;
}

static unsigned char intf_sim_inb(const struct si_sm_io *io,
unsigned int offset)
{
IPMIKCS *ik = io->addr_source_data;
uint32_t ret;

if (pcie_busy())
return 0;
if (btlock_lock(&ik->lock, 0, 1) < 0)
return 0;
switch (offset & 1) {
case 0:
ret = ik->data_out_reg;
IPMI_KCS_SET_OBF(ik->status_reg, 0);
break;
case 1:
ret = ik->status_reg;
break;
}
btlock_unlock(&ik->lock, 0);
return ret;
}

static void intf_sim_outb(const struct si_sm_io *io, unsigned int offset,
unsigned char val)
{
IPMIKCS *ik = io->addr_source_data;

if (pcie_busy())
return;
if (btlock_lock(&ik->lock, 0, 1) < 0)
return;
if (IPMI_KCS_GET_IBF(ik->status_reg))
goto out;

switch (offset & 1) {
case 0:
ik->data_in_reg = val;
ik->status_reg &= ~KCS_STATUS_CMD_DAT;
break;

case 1:
ik->cmd_reg = val;
ik->status_reg |= KCS_STATUS_CMD_DAT;
break;
}
IPMI_KCS_SET_IBF(ik->status_reg, 1);
ik->write_req++;
out:
btlock_unlock(&ik->lock, 0);
}

static void ipmi_ls2k500_cleanup(struct si_sm_io *io)
{
}

int ipmi_si_sim_setup(struct si_sm_io *io)
{
io->inputb = intf_sim_inb;
io->outputb = intf_sim_outb;
io->io_cleanup = ipmi_ls2k500_cleanup;
return 0;
}

#define platform_resource_start(dev, bar) ((dev)->resource[(bar)].start)
#define platform_resource_end(dev, bar) ((dev)->resource[(bar)].end)
static int of_ipmi_ls2k500_probe(struct platform_device *pdev)
{
int rv;
struct si_sm_io io;
void **kcs_data;

memset(&io, 0, sizeof(io));
io.addr_source = SI_PLATFORM;
dev_info(&pdev->dev, "probing via ls2k500 platform");
io.si_type = SI_KCS;

io.addr_space = IPMI_MEM_ADDR_SPACE;
io.io_setup = ipmi_si_sim_setup;
io.addr_data = pdev->resource[0].start;
io.addr_source_data = ioremap(pdev->resource[0].start,
pdev->resource[0].end -
pdev->resource[0].start + 1);
kcs_data = dev_get_platdata(&pdev->dev);
event_jiffies = kcs_data[0];
mscycles = kcs_data[1];
io.dev = &pdev->dev;
io.regspacing = 4;
io.regsize = DEFAULT_REGSIZE;
io.regshift = 0;
io.irq = 0;
if (io.irq)
io.irq_setup = ipmi_std_irq_setup;

dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
&pdev->resource[0], io.regsize, io.regspacing, io.irq);

rv = ipmi_si_add_smi(&io);
if (rv)
ipmi_si_remove_by_dev(&pdev->dev);

return rv;
}

static int ipmi_ls2k500_remove(struct platform_device *pdev)
{
ipmi_si_remove_by_dev(&pdev->dev);

return 0;
}

#define LS2K500_SI_DEVICE_NAME "ipmi_ls2k500_si"
struct platform_driver ipmi_ls2k500_platform_driver = {
.driver = {
.name = LS2K500_SI_DEVICE_NAME,
},
.probe = of_ipmi_ls2k500_probe,
.remove = ipmi_ls2k500_remove,
};

static bool platform_registered;
int ipmi_si_ls2k500_init(void)
{
int rv;

rv = platform_driver_register(&ipmi_ls2k500_platform_driver);
if (rv)
pr_err("Unable to register driver: %d\n", rv);
else
platform_registered = true;
return rv;
}

void ipmi_si_ls2k500_shutdown(void)
{
if (platform_registered)
platform_driver_unregister(&ipmi_ls2k500_platform_driver);
}
Loading