All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gregory CLEMENT <gregory.clement@bootlin.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 3/7] MSCC: add support for Ocelot SoCs
Date: Thu, 13 Dec 2018 15:05:21 +0100	[thread overview]
Message-ID: <87k1kdldy6.fsf@bootlin.com> (raw)
In-Reply-To: 9a6b0b21-85a3-da37-cb5b-b6712c7ddec6@gmail.com

Hi Daniel,
 
 On lun., déc. 10 2018, Daniel Schwierzeck <daniel.schwierzeck@gmail.com> wrote:

>> diff --git a/arch/mips/mach-mscc/include/ioremap.h b/arch/mips/mach-mscc/include/ioremap.h
>> new file mode 100644
>> index 0000000000..8ea5c65ce3
>> --- /dev/null
>> +++ b/arch/mips/mach-mscc/include/ioremap.h
>> @@ -0,0 +1,51 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>
> this line should start with a //. There are more files in this patch
> which need to be fixed.

Actually, according to the documentation (Licenses/README):
  The SPDX license identifier is added in form of a comment.  The comment
   style depends on the file type::

      C source:	// SPDX-License-Identifier: <SPDX License Expression>
      C header:	/* SPDX-License-Identifier: <SPDX License Expression> */

So for a C header file, /* comment */ is correct.

>
>> +/*
>> + * Copyright (c) 2018 Microsemi Corporation
>> + */
>> +
>> +#ifndef __ASM_MACH_MSCC_IOREMAP_H
>> +#define __ASM_MACH_MSCC_IOREMAP_H
>> +
>> +#include <linux/types.h>
>> +#include <mach/common.h>
>> +
>> +/*
>> + * Allow physical addresses to be fixed up to help peripherals located
>> + * outside the low 32-bit range -- generic pass-through version.
>> + */
>> +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr,
>> +					     phys_addr_t size)
>> +{
>> +	return phys_addr;
>> +}
>> +
>> +static inline int is_vcoreiii_internal_registers(phys_addr_t offset)
>> +{
>> +#if defined(CONFIG_ARCH_MSCC)
>
> this define is superfluous because this directory is only added to the
> include paths when CONFIG_ARCH_MSCC is selected

OK

>
>> +	if ((offset >= MSCC_IO_ORIGIN1_OFFSET &&
>> +	     offset < (MSCC_IO_ORIGIN1_OFFSET + MSCC_IO_ORIGIN1_SIZE)) ||
>> +	    (offset >= MSCC_IO_ORIGIN2_OFFSET &&
>> +	     offset < (MSCC_IO_ORIGIN2_OFFSET + MSCC_IO_ORIGIN2_SIZE)))
>> +		return 1;
>> +#endif
>> +
>> +	return 0;
>> +}

[...]

>> +/*
>> + * DDR memory sanity checking failed, tally and do hard reset
>> + *
>> + * NB: Assumes inlining as no stack is available!
>> + */
>> +static inline void hal_vcoreiii_ddr_failed(void)
>> +{
>> +	register u32 reset;
>> +
>> +	writel(readl(BASE_CFG + ICPU_GPR(6)) + 1, BASE_CFG + ICPU_GPR(6));
>> +
>> +	clrbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
>> +
>> +	/* Jump to reset - does not return */
>> +	reset = KSEG0ADDR(_machine_restart);
>> +	/* Reset while running from cache */
>> +	icache_lock((void *)reset, 128);
>> +	asm volatile ("jr %0"::"r" (reset));
>
> could you briefly describe the reason for this in a comment? It's not
> clear why this code is necessary without knowing the SoC. AFAIU from
> your last mail the boot SPI flash is mapped to KUSEG and you need to
> establish a TLB mapping in lowlevel_init() to be able to move to
> KSEG0.

The reboot workaround in _machine_restart() will change the SPI NOR
into SW bitbang.

This will render the CPU unable to execute directly from the NOR, which
is why the reset instructions are prefetched into the I-cache.

When failing the DDR initialization we are executing from NOR.

The last instruction in _machine_restart() will reset the MIPS CPU
(and the cache), and the CPU will start executing from the reset vactor.

I will add this explanation as comment.

>
>> +
>> +	panic("DDR init failed\n");
>> +}
>> +
>> +/*
>> + * DDR memory sanity checking done, possibly enable ECC.
>> + *
>> + * NB: Assumes inlining as no stack is available!
>> + */
>> +static inline void hal_vcoreiii_ddr_verified(void)
>> +{
>> +#ifdef MIPS_VCOREIII_MEMORY_ECC
>> +	/* Finally, enable ECC */
>> +	register u32 val = readl(BASE_CFG + ICPU_MEMCTRL_CFG);
>> +
>> +	val |= ICPU_MEMCTRL_CFG_DDR_ECC_ERR_ENA;
>> +	val &= ~ICPU_MEMCTRL_CFG_BURST_SIZE;
>> +
>> +	writel(val, BASE_CFG + ICPU_MEMCTRL_CFG);
>> +#endif
>> +
>> +	/* Reset Status register - sticky bits */
>> +	writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT), BASE_CFG + ICPU_MEMCTRL_STAT);
>> +}
>> +
>> +/* NB: Assumes inlining as no stack is available! */
>> +static inline int look_for(u32 bytelane)
>> +{
>> +	register u32 i;
>> +
>> +	/* Reset FIFO in case any previous access failed */
>> +	for (i = 0; i < sizeof(training_data); i++) {
>> +		register u32 byte;
>> +
>> +		memphy_soft_reset();
>> +		/* Reset sticky bits */
>> +		writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT),
>> +		       BASE_CFG + ICPU_MEMCTRL_STAT);
>> +		/* Read data */
>> +		byte = ((volatile u8 *)MSCC_DDR_TO)[bytelane + (i * 4)];
>
> __raw_readl()?

I had tried it before but without luck, but after trying harder this
time I managed to use read(b|l)/write(b|l) everywhere and get ride of
the volatile variable.

>
>> +		/*
>> +		 * Prevent the compiler reordering the instruction so
>> +		 * the read of RAM happens after the check of the
>> +		 * errors.
>> +		 */
>> +		asm volatile("" : : : "memory");
>
> this is available as barrier(). But according to context you could use
> rmb(). Anyway with the current volatile pointer or the suggested
> __raw_readl() the compiler shouldn't reorder at all

I had a close look on the code generating the __raw_readl and there is
nothing there to guaranty the ordering. Actually in our case (32 bits)
__read_readl is just:
static inline u32 __raw_readl(const volatile void __iomem *mem)
{
	u32 __val;

	__val = *mem;
	return __val;
}

initial code is here:
https://elixir.bootlin.com/u-boot/v2018.11-rc3/source/arch/mips/include/asm/io.h#L265
but __swizzle_addr_l() did nothing
https://elixir.bootlin.com/u-boot/v2018.11-rc3/source/arch/mips/include/asm/mach-generic/mangle-port.h#L10
same for __raw_ioswabl():
https://elixir.bootlin.com/u-boot/v2018.11-rc3/source/arch/mips/include/asm/io.h#L35

So the code is the same that we have written. I agree it is cleaner
to use __raw_readl but it doesn't add anything about the ordering.

It is the same for the use of the volatile, it ensures that the compiler
will always produce a operation to read the data in memory, but it is
not about ordering.

As you suggested I will use rmb();

>> +static inline int hal_vcoreiii_train_bytelane(u32 bytelane)
>> +{
>> +	register int res;
>> +	register u32 dqs_s;
>> +
>> +	set_dly(bytelane, 0);	// Start training at DQS=0
>
> no C++ style comments

OK

>
>> +	while ((res = look_for(bytelane)) == DDR_TRAIN_CONTINUE)
>> +		;
>> +	if (res != DDR_TRAIN_OK)
>> +		return res;
>> +
>> +	dqs_s = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
>> +	while ((res = look_past(bytelane)) == DDR_TRAIN_CONTINUE)
>> +		;
>> +	if (res != DDR_TRAIN_OK)
>> +		return res;
>> +	/* Reset FIFO - for good measure */
>> +	memphy_soft_reset();
>> +	/* Adjust to center [dqs_s;cur] */
>> +	center_dly(bytelane, dqs_s);
>> +	return DDR_TRAIN_OK;
>> +}
>> +
>> +/* This algorithm is converted from the TCL training algorithm used
>> + * during silicon simulation.
>> + * NB: Assumes inlining as no stack is available!
>> + */
>> +static inline int hal_vcoreiii_init_dqs(void)
>> +{
>> +#define MAX_DQS 32
>> +	register u32 i, j;
>> +
>> +	for (i = 0; i < MAX_DQS; i++) {
>> +		set_dly(0, i);	// Byte-lane 0
>
> no C++ style comments

OK

>
>> +		for (j = 0; j < MAX_DQS; j++) {
>> +			register u32 __attribute__ ((unused)) byte;
>
> why unused? If you really need it, you could use __maybe_unused

Because the purpose of this variable is just to access the memory, we
don't do nothing of the value read, and gcc complain about it. But as
you suggest I will use __maybe_unused.

>
>> +			set_dly(1, j);	// Byte-lane 1
>> +			/* Reset FIFO in case any previous access failed */
>> +			memphy_soft_reset();
>> +			writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT),
>> +			       BASE_CFG + ICPU_MEMCTRL_STAT);
>> +			byte = ((volatile u8 *)MSCC_DDR_TO)[0];
>> +			byte = ((volatile u8 *)MSCC_DDR_TO)[1];
>> +			if (!(readl(BASE_CFG + ICPU_MEMCTRL_STAT) &
>> +			    (ICPU_MEMCTRL_STAT_RDATA_MASKED |
>> +			     ICPU_MEMCTRL_STAT_RDATA_DUMMY)))
>> +				return 0;
>> +		}
>> +	}
>> +	return -1;
>> +}
>> +
>> +static inline int dram_check(void)
>> +{
>> +#define DDR ((volatile u32 *) MSCC_DDR_TO)
>> +	register u32 i;
>> +
>> +	for (i = 0; i < 8; i++) {
>> +		DDR[i] = ~i;
>> +		if (DDR[i] != ~i)
>
> __raw_readl(), __raw_writel() and drop the explicit volatile?

Yes, as explain above, it s done now.

>> +
>> +/*
>> + * Target offset base(s)
>> + */
>> +#define MSCC_IO_ORIGIN1_OFFSET 0x70000000
>> +#define MSCC_IO_ORIGIN1_SIZE   0x00200000
>> +#define MSCC_IO_ORIGIN2_OFFSET 0x71000000
>> +#define MSCC_IO_ORIGIN2_SIZE   0x01000000
>> +#define BASE_CFG        ((void __iomem *)0x70000000)
>> +#define BASE_DEVCPU_GCB ((void __iomem *)0x71070000)
>
> Would it be possible on that SoC to define those register offsets as
> simple physical address and create the mapping when needed?
> For example:
>
> void foo()
> {
>     void __iomem *base_cfg = ioremap(BASE_CFG, ...);
>     writel(base_cfg + XXX, 0);
> }

Actually creating the mapping is just casting the physical address in an
(void __iomem *), see our plat_ioremap.

Calling ioremap in every function will just grow them with little
benefit.

If you really want it, what I could is sharing void __iomem *base_cfg
and void __iomem *base_devcpu_gcb at platform level, and initialize them
only once very early during the boot.


>> +LEAF(lowlevel_init)
>> +	/*
>> +	 * As we have no stack yet, we can assume the restricted
>> +	 * luxury of the sX-registers without saving them
>> +	 */
>> +	move	s0,ra
>> +
>> +	jal	vcoreiii_tlb_init
>> +	nop
>
> we use the same style as Linux MIPS where instructions in the delay slot
> should be indented by an extra space.

OK

Thanks,

Gregory

-- 
Gregory Clement, Bootlin
Embedded Linux and Kernel engineering
http://bootlin.com

  reply	other threads:[~2018-12-13 14:05 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-05 17:10 [U-Boot] [PATCH v3 0/7] ] Add support for the SoCs found in Microsemi switches Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 1/7] MIPS: move create_tlb() in an proper header: mipsregs.h Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 2/7] MIPS: Allow to prefetch and lock instructions into cache Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 3/7] MSCC: add support for Ocelot SoCs Gregory CLEMENT
2018-12-10 16:57   ` Daniel Schwierzeck
2018-12-13 14:05     ` Gregory CLEMENT [this message]
2018-12-13 14:55       ` Daniel Schwierzeck
2018-12-05 17:10 ` [U-Boot] [PATCH v3 4/7] MSCC: add support for Luton SoCs Gregory CLEMENT
2018-12-10 17:03   ` Daniel Schwierzeck
2018-12-13 14:29     ` Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 5/7] MSCC: add board support for the Ocelots based evaluation boards Gregory CLEMENT
2018-12-10 17:17   ` Daniel Schwierzeck
2018-12-13 14:43     ` Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 6/7] MSCC: add board support for the Luton based evaluation board Gregory CLEMENT
2018-12-05 17:10 ` [U-Boot] [PATCH v3 7/7] MIPS: bootm: Add support for Vcore III linux kernel Gregory CLEMENT
2018-12-10 17:30   ` Daniel Schwierzeck
2018-12-14 10:43     ` Gregory CLEMENT

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k1kdldy6.fsf@bootlin.com \
    --to=gregory.clement@bootlin.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.