Skip to content

Commit

Permalink
dm: Add Hardware Spinlock class
Browse files Browse the repository at this point in the history
This is uclass for Hardware Spinlocks.
It implements two mandatory operations: lock and unlock
and one optional relax operation.

Signed-off-by: Benjamin Gaignard <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
Reviewed-by: Patrice Chotard <[email protected]>
  • Loading branch information
Benjamin-Gaignard authored and trini committed Dec 7, 2018
1 parent 3b074fb commit 7f84fc6
Show file tree
Hide file tree
Showing 13 changed files with 414 additions and 0 deletions.
4 changes: 4 additions & 0 deletions arch/sandbox/dts/test.dts
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,10 @@
pinctrl {
compatible = "sandbox,pinctrl";
};

hwspinlock@0 {
compatible = "sandbox,hwspinlock";
};
};

#include "sandbox_pmic.dtsi"
1 change: 1 addition & 0 deletions arch/sandbox/include/asm/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ struct sandbox_state {

ulong next_tag; /* Next address tag to allocate */
struct list_head mapmem_head; /* struct sandbox_mapmem_entry */
bool hwspinlock; /* Hardware Spinlock status */
};

/* Minimum space we guarantee in the state FDT when calling read/write*/
Expand Down
2 changes: 2 additions & 0 deletions configs/sandbox_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ CONFIG_BOARD=y
CONFIG_BOARD_SANDBOX=y
CONFIG_PM8916_GPIO=y
CONFIG_SANDBOX_GPIO=y
CONFIG_DM_HWSPINLOCK=y
CONFIG_HWSPINLOCK_SANDBOX=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_I2C_CROS_EC_LDO=y
Expand Down
2 changes: 2 additions & 0 deletions drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ source "drivers/fpga/Kconfig"

source "drivers/gpio/Kconfig"

source "drivers/hwspinlock/Kconfig"

source "drivers/i2c/Kconfig"

source "drivers/input/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions drivers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,5 @@ obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_W1_EEPROM) += w1-eeprom/

obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/
endif
16 changes: 16 additions & 0 deletions drivers/hwspinlock/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
menu "Hardware Spinlock Support"

config DM_HWSPINLOCK
bool "Enable U-Boot hardware spinlock support"
help
This option enables U-Boot hardware spinlock support

config HWSPINLOCK_SANDBOX
bool "Enable Hardware Spinlock support for Sandbox"
depends on SANDBOX && DM_HWSPINLOCK
help
Enable hardware spinlock support in Sandbox. This is a dummy device that
can be probed and support all the methods of HWSPINLOCK, but does not
really do anything.

endmenu
6 changes: 6 additions & 0 deletions drivers/hwspinlock/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
#
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved

obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o
obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o
144 changes: 144 additions & 0 deletions drivers/hwspinlock/hwspinlock-uclass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*/

#include <common.h>
#include <dm.h>
#include <errno.h>
#include <hwspinlock.h>
#include <dm/device-internal.h>

static inline const struct hwspinlock_ops *
hwspinlock_dev_ops(struct udevice *dev)
{
return (const struct hwspinlock_ops *)dev->driver->ops;
}

static int hwspinlock_of_xlate_default(struct hwspinlock *hws,
struct ofnode_phandle_args *args)
{
if (args->args_count > 1) {
debug("Invaild args_count: %d\n", args->args_count);
return -EINVAL;
}

if (args->args_count)
hws->id = args->args[0];
else
hws->id = 0;

return 0;
}

int hwspinlock_get_by_index(struct udevice *dev, int index,
struct hwspinlock *hws)
{
int ret;
struct ofnode_phandle_args args;
struct udevice *dev_hws;
const struct hwspinlock_ops *ops;

assert(hws);
hws->dev = NULL;

ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1,
index, &args);
if (ret) {
dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
__func__, ret);
return ret;
}

ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK,
args.node, &dev_hws);
if (ret) {
dev_dbg(dev,
"%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}

hws->dev = dev_hws;

ops = hwspinlock_dev_ops(dev_hws);

if (ops->of_xlate)
ret = ops->of_xlate(hws, &args);
else
ret = hwspinlock_of_xlate_default(hws, &args);
if (ret)
dev_dbg(dev, "of_xlate() failed: %d\n", ret);

return ret;
}

int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout)
{
const struct hwspinlock_ops *ops;
ulong start;
int ret;

assert(hws);

if (!hws->dev)
return -EINVAL;

ops = hwspinlock_dev_ops(hws->dev);
if (!ops->lock)
return -ENOSYS;

start = get_timer(0);
do {
ret = ops->lock(hws->dev, hws->id);
if (!ret)
return ret;

if (ops->relax)
ops->relax(hws->dev);
} while (get_timer(start) < timeout);

return -ETIMEDOUT;
}

int hwspinlock_unlock(struct hwspinlock *hws)
{
const struct hwspinlock_ops *ops;

assert(hws);

if (!hws->dev)
return -EINVAL;

ops = hwspinlock_dev_ops(hws->dev);
if (!ops->unlock)
return -ENOSYS;

return ops->unlock(hws->dev, hws->id);
}

static int hwspinlock_post_bind(struct udevice *dev)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
struct hwspinlock_ops *ops = device_get_ops(dev);
static int reloc_done;

if (!reloc_done) {
if (ops->lock)
ops->lock += gd->reloc_off;
if (ops->unlock)
ops->unlock += gd->reloc_off;
if (ops->relax)
ops->relax += gd->reloc_off;

reloc_done++;
}
#endif
return 0;
}

UCLASS_DRIVER(hwspinlock) = {
.id = UCLASS_HWSPINLOCK,
.name = "hwspinlock",
.post_bind = hwspinlock_post_bind,
};
56 changes: 56 additions & 0 deletions drivers/hwspinlock/sandbox_hwspinlock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*/

#include <common.h>
#include <dm.h>
#include <hwspinlock.h>
#include <asm/state.h>

static int sandbox_lock(struct udevice *dev, int index)
{
struct sandbox_state *state = state_get_current();

if (index != 0)
return -1;

if (state->hwspinlock)
return -1;

state->hwspinlock = true;

return 0;
}

static int sandbox_unlock(struct udevice *dev, int index)
{
struct sandbox_state *state = state_get_current();

if (index != 0)
return -1;

if (!state->hwspinlock)
return -1;

state->hwspinlock = false;

return 0;
}

static const struct hwspinlock_ops sandbox_hwspinlock_ops = {
.lock = sandbox_lock,
.unlock = sandbox_unlock,
};

static const struct udevice_id sandbox_hwspinlock_ids[] = {
{ .compatible = "sandbox,hwspinlock" },
{}
};

U_BOOT_DRIVER(hwspinlock_sandbox) = {
.name = "hwspinlock_sandbox",
.id = UCLASS_HWSPINLOCK,
.of_match = sandbox_hwspinlock_ids,
.ops = &sandbox_hwspinlock_ops,
};
1 change: 1 addition & 0 deletions include/dm/uclass-id.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum uclass_id {
UCLASS_FIRMWARE, /* Firmware */
UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_GPIO, /* Bank of general-purpose I/O pins */
UCLASS_HWSPINLOCK, /* Hardware semaphores */
UCLASS_I2C, /* I2C bus */
UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_I2C_GENERIC, /* Generic I2C device */
Expand Down
Loading

0 comments on commit 7f84fc6

Please sign in to comment.