Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2cda3ac4 authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

clocksource: sh_cmt: Split static information from sh_cmt_device



Create a new sh_cmt_info structure to hold static information about the
device model and reference that structure from the sh_cmt_device
structure.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
parent f5ec9b19
Loading
Loading
Loading
Loading
+122 −70
Original line number Diff line number Diff line
@@ -37,6 +37,52 @@

struct sh_cmt_device;

/*
 * The CMT comes in 5 different identified flavours, depending not only on the
 * SoC but also on the particular instance. The following table lists the main
 * characteristics of those flavours.
 *
 *			16B	32B	32B-F	48B	48B-2
 * -----------------------------------------------------------------------------
 * Channels		2	1/4	1	6	2/8
 * Control Width	16	16	16	16	32
 * Counter Width	16	32	32	32/48	32/48
 * Shared Start/Stop	Y	Y	Y	Y	N
 *
 * The 48-bit gen2 version has a per-channel start/stop register located in the
 * channel registers block. All other versions have a shared start/stop register
 * located in the global space.
 *
 * Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit
 * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable.
 */

enum sh_cmt_model {
	SH_CMT_16BIT,
	SH_CMT_32BIT,
	SH_CMT_32BIT_FAST,
	SH_CMT_48BIT,
	SH_CMT_48BIT_GEN2,
};

struct sh_cmt_info {
	enum sh_cmt_model model;

	unsigned long width; /* 16 or 32 bit version of hardware block */
	unsigned long overflow_bit;
	unsigned long clear_bits;

	/* callbacks for CMSTR and CMCSR access */
	unsigned long (*read_control)(void __iomem *base, unsigned long offs);
	void (*write_control)(void __iomem *base, unsigned long offs,
			      unsigned long value);

	/* callbacks for CMCNT and CMCOR access */
	unsigned long (*read_count)(void __iomem *base, unsigned long offs);
	void (*write_count)(void __iomem *base, unsigned long offs,
			    unsigned long value);
};

struct sh_cmt_channel {
	struct sh_cmt_device *cmt;
	unsigned int index;
@@ -58,49 +104,16 @@ struct sh_cmt_channel {
struct sh_cmt_device {
	struct platform_device *pdev;

	const struct sh_cmt_info *info;

	void __iomem *mapbase_ch;
	void __iomem *mapbase;
	struct clk *clk;

	struct sh_cmt_channel *channels;
	unsigned int num_channels;

	unsigned long width; /* 16 or 32 bit version of hardware block */
	unsigned long overflow_bit;
	unsigned long clear_bits;

	/* callbacks for CMSTR and CMCSR access */
	unsigned long (*read_control)(void __iomem *base, unsigned long offs);
	void (*write_control)(void __iomem *base, unsigned long offs,
			      unsigned long value);

	/* callbacks for CMCNT and CMCOR access */
	unsigned long (*read_count)(void __iomem *base, unsigned long offs);
	void (*write_count)(void __iomem *base, unsigned long offs,
			    unsigned long value);
};

/* Examples of supported CMT timer register layouts and I/O access widths:
 *
 * "16-bit counter and 16-bit control" as found on sh7263:
 * CMSTR 0xfffec000 16-bit
 * CMCSR 0xfffec002 16-bit
 * CMCNT 0xfffec004 16-bit
 * CMCOR 0xfffec006 16-bit
 *
 * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740:
 * CMSTR 0xffca0000 16-bit
 * CMCSR 0xffca0060 16-bit
 * CMCNT 0xffca0064 32-bit
 * CMCOR 0xffca0068 32-bit
 *
 * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790:
 * CMSTR 0xffca0500 32-bit
 * CMCSR 0xffca0510 32-bit
 * CMCNT 0xffca0514 32-bit
 * CMCOR 0xffca0518 32-bit
 */

static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
{
	return ioread16(base + (offs << 1));
@@ -123,47 +136,100 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,
	iowrite32(value, base + (offs << 2));
}

static const struct sh_cmt_info sh_cmt_info[] = {
	[SH_CMT_16BIT] = {
		.model = SH_CMT_16BIT,
		.width = 16,
		.overflow_bit = 0x80,
		.clear_bits = ~0x80,
		.read_control = sh_cmt_read16,
		.write_control = sh_cmt_write16,
		.read_count = sh_cmt_read16,
		.write_count = sh_cmt_write16,
	},
	[SH_CMT_32BIT] = {
		.model = SH_CMT_32BIT,
		.width = 32,
		.overflow_bit = 0x8000,
		.clear_bits = ~0xc000,
		.read_control = sh_cmt_read16,
		.write_control = sh_cmt_write16,
		.read_count = sh_cmt_read32,
		.write_count = sh_cmt_write32,
	},
	[SH_CMT_32BIT_FAST] = {
		.model = SH_CMT_32BIT_FAST,
		.width = 32,
		.overflow_bit = 0x8000,
		.clear_bits = ~0xc000,
		.read_control = sh_cmt_read16,
		.write_control = sh_cmt_write16,
		.read_count = sh_cmt_read32,
		.write_count = sh_cmt_write32,
	},
	[SH_CMT_48BIT] = {
		.model = SH_CMT_48BIT,
		.width = 32,
		.overflow_bit = 0x8000,
		.clear_bits = ~0xc000,
		.read_control = sh_cmt_read32,
		.write_control = sh_cmt_write32,
		.read_count = sh_cmt_read32,
		.write_count = sh_cmt_write32,
	},
	[SH_CMT_48BIT_GEN2] = {
		.model = SH_CMT_48BIT_GEN2,
		.width = 32,
		.overflow_bit = 0x8000,
		.clear_bits = ~0xc000,
		.read_control = sh_cmt_read32,
		.write_control = sh_cmt_write32,
		.read_count = sh_cmt_read32,
		.write_count = sh_cmt_write32,
	},
};

#define CMCSR 0 /* channel register */
#define CMCNT 1 /* channel register */
#define CMCOR 2 /* channel register */

static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
{
	return ch->cmt->read_control(ch->cmt->mapbase, 0);
	return ch->cmt->info->read_control(ch->cmt->mapbase, 0);
}

static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
{
	return ch->cmt->read_control(ch->base, CMCSR);
	return ch->cmt->info->read_control(ch->base, CMCSR);
}

static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
{
	return ch->cmt->read_count(ch->base, CMCNT);
	return ch->cmt->info->read_count(ch->base, CMCNT);
}

static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
				      unsigned long value)
{
	ch->cmt->write_control(ch->cmt->mapbase, 0, value);
	ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
}

static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch,
				      unsigned long value)
{
	ch->cmt->write_control(ch->base, CMCSR, value);
	ch->cmt->info->write_control(ch->base, CMCSR, value);
}

static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch,
				      unsigned long value)
{
	ch->cmt->write_count(ch->base, CMCNT, value);
	ch->cmt->info->write_count(ch->base, CMCNT, value);
}

static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch,
				      unsigned long value)
{
	ch->cmt->write_count(ch->base, CMCOR, value);
	ch->cmt->info->write_count(ch->base, CMCOR, value);
}

static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
@@ -172,7 +238,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
	unsigned long v1, v2, v3;
	int o1, o2;

	o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
	o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;

	/* Make sure the timer value is stable. Stolen from acpi_pm.c */
	do {
@@ -180,7 +246,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
		v1 = sh_cmt_read_cmcnt(ch);
		v2 = sh_cmt_read_cmcnt(ch);
		v3 = sh_cmt_read_cmcnt(ch);
		o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
		o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
	} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
			  || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));

@@ -227,7 +293,7 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
	sh_cmt_start_stop_ch(ch, 0);

	/* configure channel, periodic mode and maximum timeout */
	if (ch->cmt->width == 16) {
	if (ch->cmt->info->width == 16) {
		*rate = clk_get_rate(ch->cmt->clk) / 512;
		sh_cmt_write_cmcsr(ch, 0x43);
	} else {
@@ -405,7 +471,8 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
	struct sh_cmt_channel *ch = dev_id;

	/* clear flags */
	sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & ch->cmt->clear_bits);
	sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) &
			   ch->cmt->info->clear_bits);

	/* update clock source counter to begin with if enabled
	 * the wrap flag should be cleared by the timer specific
@@ -719,10 +786,10 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
		return irq;
	}

	if (cmt->width == (sizeof(ch->max_match_value) * 8))
	if (cmt->info->width == (sizeof(ch->max_match_value) * 8))
		ch->max_match_value = ~0;
	else
		ch->max_match_value = (1 << cmt->width) - 1;
		ch->max_match_value = (1 << cmt->info->width) - 1;

	ch->match_value = ch->max_match_value;
	raw_spin_lock_init(&ch->lock);
@@ -800,28 +867,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
	if (ret < 0)
		goto err3;

	if (res2 && (resource_size(res2) == 4)) {
		/* assume both CMSTR and CMCSR to be 32-bit */
		cmt->read_control = sh_cmt_read32;
		cmt->write_control = sh_cmt_write32;
	} else {
		cmt->read_control = sh_cmt_read16;
		cmt->write_control = sh_cmt_write16;
	}

	if (resource_size(res) == 6) {
		cmt->width = 16;
		cmt->read_count = sh_cmt_read16;
		cmt->write_count = sh_cmt_write16;
		cmt->overflow_bit = 0x80;
		cmt->clear_bits = ~0x80;
	} else {
		cmt->width = 32;
		cmt->read_count = sh_cmt_read32;
		cmt->write_count = sh_cmt_write32;
		cmt->overflow_bit = 0x8000;
		cmt->clear_bits = ~0xc000;
	}
	/* identify the model based on the resources */
	if (resource_size(res) == 6)
		cmt->info = &sh_cmt_info[SH_CMT_16BIT];
	else if (res2 && (resource_size(res2) == 4))
		cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2];
	else
		cmt->info = &sh_cmt_info[SH_CMT_32BIT];

	cmt->channels = kzalloc(sizeof(*cmt->channels), GFP_KERNEL);
	if (cmt->channels == NULL) {