Re: [U-Boot] [PATCH 1/4] ARM: fix the ARCH Timer frequency setting.

2014-07-04 Thread Diana Craciun

On 07/04/2014 04:43 AM, Xiubo Li-B47053 wrote:

Subject: Re: [PATCH 1/4] ARM: fix the ARCH Timer frequency setting.

On 07/03/2014 12:51 PM, Xiubo Li wrote:

For some SoCs, the CONFIG_SYS_CLK_FREQ maybe won't equal the ARCH
Timer's frequency.

Can you give an example?


In LS1021A-QDS/TWR, the CONFIG_SYS_CLK_FREQ is 100Mhz and the ARCH timer's
Frequency will be 12.5Mhz...



Here using the CONFIG_TIMER_CLK_FREQ instead if the ARCH Timer's
frequency need to config here.

Signed-off-by: Xiubo Li li.xi...@freescale.com
---
   arch/arm/cpu/armv7/nonsec_virt.S | 4 ++--
   1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/armv7/nonsec_virt.S

b/arch/arm/cpu/armv7/nonsec_virt.S

index 6f90988..e9766c0 100644
--- a/arch/arm/cpu/armv7/nonsec_virt.S
+++ b/arch/arm/cpu/armv7/nonsec_virt.S
@@ -147,11 +147,11 @@ ENTRY(_nonsec_init)
* we do this here instead.
* But first check if we have the generic timer.
*/
-#ifdef CONFIG_SYS_CLK_FREQ
+#ifdef CONFIG_TIMER_CLK_FREQ

Aren't you breaking the boards which rely on CONFIG_SYS_CLK_FREQ ?

I hadn't found any board is using this in the upstreamed tree, or may
I miss something ?

If there exist some, and I will redefined it for them here.

In ARMv7, what could I find is that only vexpress_ca15_tc2 board has enabled
the CONFIG_ARMV7_VIRT without defining it.


Yes, this board defines CONFIG_ARMV7_VIRT. In order for this board to 
work after your changes you need to define CONFIG_TIMER_CLK_FREQ.


Diana

___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 3/4] ARM: LS1021A: enable ARMv7 virt support for LS1021A A7

2014-07-04 Thread Diana Craciun

On 07/04/2014 04:48 AM, Xiubo Li-B47053 wrote:

diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index d639a6f..f090971 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -18,6 +18,15 @@
   #define CONFIG_BOARD_EARLY_INIT_F
   #define CONFIG_ARCH_EARLY_INIT_R

+#define CONFIG_ARMV7_NONSEC
+#define CONFIG_ARMV7_VIRT
+#define CONFIG_SOC_BIG_ENDIAN
+#define CONFIG_DCFG_CCSR_SCRATCHRW10x01ee0200
+#define CONFIG_DCFG_CCSR_BRR   0x01ee00e4

Why are you hardcoding the register addresses in this file? I saw that
all registers are defined in:
arch/arm/include/asm/arch-ls102xa/config.h. Why are these special?


No special, and I'll follow your advice.



+#define CONFIG_SMP_PEN_ADDRCONFIG_DCFG_CCSR_SCRATCHRW1
+#define CONFIG_ARM_GIC_BASE_ADDRESS0x0140

Why do you need the GIC base address? Can't this be read from CBAR?


I'm not very sure, I have tried, but failed, I will do some research later.


What is not working? Is the address returned by CBAR wrong?

Diana
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 0/4] Add LS1021A-QDS/TWR Non-secure and HYP support.

2014-07-04 Thread Diana Craciun

On 07/04/2014 04:31 AM, Xiubo Li-B47053 wrote:

This patch series depends on the following patch:

[U-Boot,v4,03/10] ARM: non-sec: reset CNTVOFF to zero

Before switching to non-secure, make sure that CNTVOFF is set
to zero on all CPUs. Otherwise, kernel running in non-secure
without HYP enabled (hence using virtual timers) may observe

But we have HYP enabled. In this case why are the series dependent on
this patch?


Well, if the HYP is enabled, the host OS will use the Physical timer,
and these CNTVOFFs could be cleared in kernel too.

When and where to clear them is better ? In uboot or in kernel when needed?


If HYP mode is available CNTVOFF is cleared in Linux. What I am trying 
to say is that it will work also without the patch you mentioned.


Diana
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 0/4] Add LS1021A-QDS/TWR Non-secure and HYP support.

2014-07-03 Thread Diana Craciun

On 07/03/2014 12:51 PM, Xiubo Li wrote:

This patch series depends on the following patch:

[U-Boot,v4,03/10] ARM: non-sec: reset CNTVOFF to zero

Before switching to non-secure, make sure that CNTVOFF is set
to zero on all CPUs. Otherwise, kernel running in non-secure
without HYP enabled (hence using virtual timers) may observe


But we have HYP enabled. In this case why are the series dependent on 
this patch?



timers that are not synchronized, effectively seeing time
going backward...



Patch work:
http://patchwork.ozlabs.org/patch/343084/





Xiubo Li (4):
   ARM: fix the ARCH Timer frequency setting.
   ARM: add the pen address byte reverting support.
   ARM: LS1021A: enable ARMv7 virt support for LS1021A A7
   ARM: LS1021A: to allow non-secure R/W access for all devices' mapped
 region

  arch/arm/cpu/armv7/ls102xa/cpu.c  |  12 +++
  arch/arm/cpu/armv7/nonsec_virt.S  |   7 +-
  arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h |  98 +--
  board/freescale/ls1021aqds/ls1021aqds.c   | 110 +++--
  board/freescale/ls1021atwr/ls1021atwr.c   | 111 --
  include/configs/ls1021aqds.h  |   9 ++
  include/configs/ls1021atwr.h  |   9 ++
  7 files changed, 333 insertions(+), 23 deletions(-)


Diana

___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 1/4] ARM: fix the ARCH Timer frequency setting.

2014-07-03 Thread Diana Craciun

On 07/03/2014 12:51 PM, Xiubo Li wrote:

For some SoCs, the CONFIG_SYS_CLK_FREQ maybe won't equal the ARCH
Timer's frequency.


Can you give an example?


Here using the CONFIG_TIMER_CLK_FREQ instead if the ARCH Timer's
frequency need to config here.

Signed-off-by: Xiubo Li li.xi...@freescale.com
---
  arch/arm/cpu/armv7/nonsec_virt.S | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S
index 6f90988..e9766c0 100644
--- a/arch/arm/cpu/armv7/nonsec_virt.S
+++ b/arch/arm/cpu/armv7/nonsec_virt.S
@@ -147,11 +147,11 @@ ENTRY(_nonsec_init)
   * we do this here instead.
   * But first check if we have the generic timer.
   */
-#ifdef CONFIG_SYS_CLK_FREQ
+#ifdef CONFIG_TIMER_CLK_FREQ


Aren't you breaking the boards which rely on CONFIG_SYS_CLK_FREQ ?


mrc p15, 0, r0, c0, c1, 1   @ read ID_PFR1
and r0, r0, #CPUID_ARM_GENTIMER_MASK@ mask arch timer bits
cmp r0, #(1  CPUID_ARM_GENTIMER_SHIFT)
-   ldreq   r1, =CONFIG_SYS_CLK_FREQ
+   ldreq   r1, =CONFIG_TIMER_CLK_FREQ
mcreq   p15, 0, r1, c14, c0, 0  @ write CNTFRQ
  #endif
  


Diana


___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 3/4] ARM: LS1021A: enable ARMv7 virt support for LS1021A A7

2014-07-03 Thread Diana Craciun

On 07/03/2014 12:51 PM, Xiubo Li wrote:

To enable hypervisors utilizing the ARMv7 virtualization extension
on the LS1021A-QDS/TWR boards with the A7 core tile, we add the
required configuration variable.
Also we define the board specific smp_set_cpu_boot_addr() function to
set the start address for secondary cores in the LS1021A specific
manner.

Signed-off-by: Xiubo Li li.xi...@freescale.com
---
  arch/arm/cpu/armv7/ls102xa/cpu.c | 12 
  include/configs/ls1021aqds.h |  9 +
  include/configs/ls1021atwr.h |  9 +
  3 files changed, 30 insertions(+)

diff --git a/arch/arm/cpu/armv7/ls102xa/cpu.c b/arch/arm/cpu/armv7/ls102xa/cpu.c
index f9046c6..2268f15 100644
--- a/arch/arm/cpu/armv7/ls102xa/cpu.c
+++ b/arch/arm/cpu/armv7/ls102xa/cpu.c
@@ -101,3 +101,15 @@ int cpu_eth_init(bd_t *bis)
  
  	return 0;

  }
+
+#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT)
+/* Setting the address at which secondary cores start from.*/
+void smp_set_core_boot_addr(unsigned long addr, int corenr)
+{
+   /* After setting the secondary cores start address, just release
+* them to boot.
+*/
+   out_be32(CONFIG_DCFG_CCSR_SCRATCHRW1, addr);
+   out_be32(CONFIG_DCFG_CCSR_BRR, 0x2);
+}
+#endif
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index d639a6f..f090971 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -18,6 +18,15 @@
  #define CONFIG_BOARD_EARLY_INIT_F
  #define CONFIG_ARCH_EARLY_INIT_R
  
+#define CONFIG_ARMV7_NONSEC

+#define CONFIG_ARMV7_VIRT
+#define CONFIG_SOC_BIG_ENDIAN
+#define CONFIG_DCFG_CCSR_SCRATCHRW10x01ee0200
+#define CONFIG_DCFG_CCSR_BRR   0x01ee00e4


Why are you hardcoding the register addresses in this file? I saw that 
all registers are defined in: 
arch/arm/include/asm/arch-ls102xa/config.h. Why are these special?




+#define CONFIG_SMP_PEN_ADDRCONFIG_DCFG_CCSR_SCRATCHRW1
+#define CONFIG_ARM_GIC_BASE_ADDRESS0x0140


Why do you need the GIC base address? Can't this be read from CBAR?


+#define CONFIG_TIMER_CLK_FREQ  12500
+
  #define CONFIG_HWCONFIG
  #define HWCONFIG_BUFFER_SIZE   128
  
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h

index a8dc56e..235a862 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -18,6 +18,15 @@
  #define CONFIG_BOARD_EARLY_INIT_F
  #define CONFIG_ARCH_EARLY_INIT_R
  
+#define CONFIG_ARMV7_NONSEC

+#define CONFIG_ARMV7_VIRT
+#define CONFIG_SOC_BIG_ENDIAN
+#define CONFIG_DCFG_CCSR_SCRATCHRW10x01ee0200
+#define CONFIG_DCFG_CCSR_BRR   0x01ee00e4
+#define CONFIG_SMP_PEN_ADDRCONFIG_DCFG_CCSR_SCRATCHRW1
+#define CONFIG_ARM_GIC_BASE_ADDRESS0x0140
+#define CONFIG_TIMER_CLK_FREQ  12500
+
  #define CONFIG_HWCONFIG
  #define HWCONFIG_BUFFER_SIZE   128
  

___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 4/4] ARM: LS1021A: to allow non-secure R/W access for all devices' mapped region

2014-07-03 Thread Diana Craciun
,
+   CSU_CSLX_WDT2, CSU_NS_SUP_RW,
+   CSU_CSLX_WDT1, CSU_NS_SUP_RW,
+   CSU_CSLX_EDMA, CSU_NS_SUP_RW,
+   CSU_CSLX_SYS_CNT, CSU_NS_SUP_RW,
+   CSU_CSLX_DMA_MUX2, CSU_NS_SUP_RW,
+   CSU_CSLX_DMA_MUX1, CSU_NS_SUP_RW,
+   CSU_CSLX_DDR, CSU_NS_SUP_RW,
+   CSU_CSLX_QUICC, CSU_NS_SUP_RW,
+   CSU_CSLX_DCFG_CCU_RCPM, CSU_NS_SUP_RW,
+   CSU_CSLX_SECURE_BOOTROM, CSU_NS_SUP_RW,
+   CSU_CSLX_SFP, CSU_NS_SUP_RW,
+   CSU_CSLX_TMU, CSU_NS_SUP_RW,
+   CSU_CSLX_SECURE_MONITOR, CSU_NS_SUP_RW,
+   CSU_CSLX_RESERVED0, CSU_NS_SUP_RW,
+   CSU_CSLX_ETSEC1, CSU_NS_SUP_RW,
+   CSU_CSLX_SEC5_5, CSU_NS_SUP_RW,
+   CSU_CSLX_ETSEC3, CSU_NS_SUP_RW,
+   CSU_CSLX_ETSEC2, CSU_NS_SUP_RW,
+   CSU_CSLX_GPIO2, CSU_NS_SUP_RW,
+   CSU_CSLX_GPIO1, CSU_NS_SUP_RW,
+   CSU_CSLX_GPIO4, CSU_NS_SUP_RW,
+   CSU_CSLX_GPIO3, CSU_NS_SUP_RW,
+   CSU_CSLX_PLATFORM_CONT, CSU_NS_SUP_RW,
+   CSU_CSLX_CSU, CSU_NS_SUP_RW,
+   CSU_CSLX_ASRC, CSU_NS_SUP_RW,
+   CSU_CSLX_SPDIF, CSU_NS_SUP_RW,
+   CSU_CSLX_FLEXCAN2, CSU_NS_SUP_RW,
+   CSU_CSLX_FLEXCAN1, CSU_NS_SUP_RW,
+   CSU_CSLX_FLEXCAN4, CSU_NS_SUP_RW,
+   CSU_CSLX_FLEXCAN3, CSU_NS_SUP_RW,
+   CSU_CSLX_SAI2, CSU_NS_SUP_RW,
+   CSU_CSLX_SAI1, CSU_NS_SUP_RW,
+   CSU_CSLX_SAI4, CSU_NS_SUP_RW,
+   CSU_CSLX_SAI3, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM2, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM1, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM4, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM3, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM6, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM5, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM8, CSU_NS_SUP_RW,
+   CSU_CSLX_FTM7, CSU_NS_SUP_RW,
+   CSU_CSLX_COP_DCSR, CSU_NS_SUP_RW,
+   CSU_CSLX_EPU, CSU_NS_SUP_RW,
+   CSU_CSLX_GDI, CSU_NS_SUP_RW,
+   CSU_CSLX_DDI, CSU_NS_SUP_RW,
+   CSU_CSLX_RESERVED1, CSU_NS_SUP_RW,
+   CSU_CSLX_USB3_PHY, CSU_NS_SUP_RW,
+   CSU_CSLX_RESERVED2, CSU_NS_SUP_RW,
+};
  
-	reg = in_be32(csu_csl2);

-   out_be32(csu_csl2, reg | CSU_CSL2x_NS_SUP_READ_ACCESS |
-   CSU_CSL2x_NS_USER_READ_ACCESS);
+void enable_devices_ns_access(void)


This function is identical for twr and qds? Can't be just one in a 
common file?



+{
+   uint32_t *csu_csl;
+   uint32_t reg;
+   int i;
+
+   for (i = 0; i  ARRAY_SIZE(ns_dev); i++) {
+   csu_csl = CONFIG_SYS_FSL_CSU_ADDR + ns_dev[i].ind / 2 * 4;
+   reg = in_be32(csu_csl);
+   if (ns_dev[i].ind % 2 == 0)
+   reg |= ns_dev[i].val  16;
+   else
+   reg |= ns_dev[i].val;
+   out_be32(csu_csl, reg);
+   }
  }
  
  int board_late_init(void)

@@ -483,7 +580,7 @@ int board_late_init(void)
  
  	ahci_init(AHCI_BASE_ADDR);

scsi_scan(1);
-   enable_ifc_ns_read_access();
+   enable_devices_ns_access();
return 0;
  }


Diana Craciun

  

___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH 1/9] arm: ls102xa: Add Freescale LS102xA SoC support

2014-06-03 Thread Diana Craciun

On 05/30/2014 10:22 AM, Alison Wang wrote:

The QorIQ LS1 family is built on Layerscape architecture,
the industry's first software-aware, core-agnostic networking
architecture to offer unprecedented efficiency and scale.

Freescale LS102xA is a set of SoCs combines two ARM
Cortex-A7 cores that have been optimized for high
reliability and pack the highest level of integration
available for sub-3 W embedded communications processors
with Layerscape architecture and with a comprehensive
enablement model focused on ease of programmability.

Signed-off-by: Alison Wang alison.w...@freescale.com
Signed-off-by: Jason Jin jason@freescale.com
Signed-off-by: Jingchang Lu jingchang...@freescale.com
Signed-off-by: Prabhakar Kushwaha prabha...@freescale.com
---
  arch/arm/cpu/armv7/ls102xa/Makefile   |  11 +
  arch/arm/cpu/armv7/ls102xa/clock.c| 131 +++
  arch/arm/cpu/armv7/ls102xa/cpu.c  | 102 ++
  arch/arm/cpu/armv7/ls102xa/fdt.c  |  82 +
  arch/arm/cpu/armv7/ls102xa/timer.c| 129 +++
  arch/arm/include/asm/arch-ls102xa/clock.h |  23 ++
  arch/arm/include/asm/arch-ls102xa/config.h|  70 
  arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h | 420 ++
  arch/arm/include/asm/arch-ls102xa/imx-regs.h  |  53 +++
  arch/arm/include/asm/config.h |   4 +
  arch/arm/include/asm/io.h |   8 +-
  drivers/watchdog/Makefile |   2 +-
  12 files changed, 1033 insertions(+), 2 deletions(-)
  create mode 100644 arch/arm/cpu/armv7/ls102xa/Makefile
  create mode 100644 arch/arm/cpu/armv7/ls102xa/clock.c
  create mode 100644 arch/arm/cpu/armv7/ls102xa/cpu.c
  create mode 100644 arch/arm/cpu/armv7/ls102xa/fdt.c
  create mode 100644 arch/arm/cpu/armv7/ls102xa/timer.c
  create mode 100644 arch/arm/include/asm/arch-ls102xa/clock.h
  create mode 100644 arch/arm/include/asm/arch-ls102xa/config.h
  create mode 100644 arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h
  create mode 100644 arch/arm/include/asm/arch-ls102xa/imx-regs.h

diff --git a/arch/arm/cpu/armv7/ls102xa/Makefile 
b/arch/arm/cpu/armv7/ls102xa/Makefile
new file mode 100644
index 000..7ef793a
--- /dev/null
+++ b/arch/arm/cpu/armv7/ls102xa/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2014 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier:  GPL-2.0+
+#
+
+obj-y  += cpu.o
+obj-y  += clock.o
+obj-y  += timer.o
+
+obj-$(CONFIG_OF_LIBFDT)+= fdt.o
diff --git a/arch/arm/cpu/armv7/ls102xa/clock.c 
b/arch/arm/cpu/armv7/ls102xa/clock.c
new file mode 100644
index 000..75bb0e9
--- /dev/null
+++ b/arch/arm/cpu/armv7/ls102xa/clock.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:GPL-2.0+
+ */
+
+#include common.h
+#include asm/io.h
+#include asm/arch/immap_ls102xa.h
+#include asm/arch/clock.h
+#include fsl_ifc.h
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS
+#define CONFIG_SYS_FSL_NUM_CC_PLLS  2
+#endif
+
+void get_sys_info(struct sys_info *sys_info)
+{
+   struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+#ifdef CONFIG_FSL_IFC
+   struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR;
+   u32 ccr;
+#endif
+   struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_LS1_CLK_ADDR);
+   unsigned int cpu;
+   const u8 core_cplx_pll[6] = {
+   [0] = 0,/* CC1 PPL / 1 */
+   [1] = 0,/* CC1 PPL / 2 */
+   [4] = 1,/* CC2 PPL / 1 */
+   [5] = 1,/* CC2 PPL / 2 */
+   };
+
+   const u8 core_cplx_pll_div[6] = {
+   [0] = 1,/* CC1 PPL / 1 */
+   [1] = 2,/* CC1 PPL / 2 */
+   [4] = 1,/* CC2 PPL / 1 */
+   [5] = 2,/* CC2 PPL / 2 */
+   };
+
+   uint i;
+   uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
+   uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
+   unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
+
+   sys_info-freq_systembus = sysclk;
+#ifdef CONFIG_DDR_CLK_FREQ
+   sys_info-freq_ddrbus = CONFIG_DDR_CLK_FREQ;
+#else
+   sys_info-freq_ddrbus = sysclk;
+#endif
+
+   sys_info-freq_systembus *= (in_be32(gur-rcwsr[0]) 
+   RCWSR0_SYS_PLL_RAT_SHIFT)  RCWSR0_SYS_PLL_RAT_MASK;
+   sys_info-freq_ddrbus *= (in_be32(gur-rcwsr[0]) 
+   RCWSR0_MEM_PLL_RAT_SHIFT)  RCWSR0_MEM_PLL_RAT_MASK;
+
+   for (i = 0; i  CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
+   ratio[i] = (in_be32(clk-pllcgsr[i].pllcngsr)  1)  0x3f;
+   if (ratio[i]  4)
+   freq_c_pll[i] = sysclk * ratio[i];
+   else
+   freq_c_pll[i] = sys_info-freq_systembus * ratio[i];
+   }
+
+   for (cpu = 0; cpu  CONFIG_MAX_CPUS; cpu++) {
+   u32 c_pll_sel = (in_be32(clk-clkcsr[cpu].clkcncsr)  27)
+