Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
ezynq
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
ezynq
Commits
4bbaac41
Commit
4bbaac41
authored
Mar 03, 2016
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nand spl support - tmp working with nand_base.c
parent
e47e7650
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
4228 additions
and
96 deletions
+4228
-96
slcr.c
u-boot-tree/arch/arm/mach-zynq/slcr.c
+0
-2
Makefile
u-boot-tree/drivers/mtd/nand/Makefile
+3
-0
elphel393_nand_spl.c
u-boot-tree/drivers/mtd/nand/elphel393_nand_spl.c
+105
-70
nand_base.c
u-boot-tree/drivers/mtd/nand/nand_base.c
+4047
-0
zynq_nand.c
u-boot-tree/drivers/mtd/nand/zynq_nand.c
+42
-3
elphel393.h
u-boot-tree/include/configs/elphel393.h
+31
-21
No files found.
u-boot-tree/arch/arm/mach-zynq/slcr.c
View file @
4bbaac41
...
...
@@ -257,8 +257,6 @@ void zynq_slcr_devcfg_enable(void)
u32
zynq_slcr_get_boot_mode
(
void
)
{
/* Get the bootmode register value */
printf
(
"
\n
BOOTMODE CODE is %d
\n
"
,(
u32
)
readl
(
&
slcr_base
->
boot_mode
));
udelay
(
5000
);
return
readl
(
&
slcr_base
->
boot_mode
);
}
...
...
u-boot-tree/drivers/mtd/nand/Makefile
View file @
4bbaac41
...
...
@@ -17,9 +17,12 @@ obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE)
+=
nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_ELPHEL393)
+=
elphel393_nand_spl.o
obj-$(CONFIG_SPL_NAND_LOAD)
+=
nand_spl_load.o
obj-$(CONFIG_SPL_NAND_BBT)
+=
nand_bbt.o
obj-$(CONFIG_SPL_NAND_IDS)
+=
nand_ids.o
obj-$(CONFIG_SPL_NAND_ECC)
+=
nand_ecc.o
obj-$(CONFIG_SPL_NAND_BASE)
+=
nand_base.o
obj-$(CONFIG_SPL_NAND_INIT)
+=
nand.o
obj-$(CONFIG_SPL_NAND_INIT)
+=
../mtdcore.o
../mtd_uboot.o
ifeq
($(CONFIG_SPL_ENV_SUPPORT),y)
obj-$(CONFIG_ENV_IS_IN_NAND)
+=
nand_util.o
endif
...
...
u-boot-tree/drivers/mtd/nand/elphel393_nand_spl.c
View file @
4bbaac41
/*
* Xilinx Zynq NAND Flash Controller Driver
* This driver is based on plat_nand.c and mxc_nand.c drivers
* Elphel393 NAND driver for SPL, not based on denali_spl.c
*
* Copyright (C) 20
09 - 2013 Xilinx
, Inc.
* Copyright (C) 20
16 Elphel
, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
...
...
@@ -19,82 +18,118 @@
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
/* The NAND flash driver defines */
#define ZYNQ_NAND_CMD_PHASE 1
/* End command valid in command phase */
#define ZYNQ_NAND_DATA_PHASE 2
/* End command valid in data phase */
#define ZYNQ_NAND_ECC_SIZE 512
/* Size of data for ECC operation */
/* Flash memory controller operating parameters */
#define ZYNQ_NAND_CLR_CONFIG ((0x1 << 1) |
/* Disable interrupt */
\
(0x1 << 4) |
/* Clear interrupt */
\
(0x1 << 6))
/* Disable ECC interrupt */
/* Assuming 50MHz clock (20ns cycle time) and 3V operation */
#define ZYNQ_NAND_SET_CYCLES ((0x2 << 20) |
/* t_rr from nand_cycles */
\
(0x2 << 17) |
/* t_ar from nand_cycles */
\
(0x1 << 14) |
/* t_clr from nand_cycles */
\
(0x3 << 11) |
/* t_wp from nand_cycles */
\
(0x2 << 8) |
/* t_rea from nand_cycles */
\
(0x5 << 4) |
/* t_wc from nand_cycles */
\
(0x5 << 0))
/* t_rc from nand_cycles */
#define ZYNQ_NAND_SET_OPMODE 0x0
#define ZYNQ_NAND_DIRECT_CMD ((0x4 << 23) |
/* Chip 0 from interface 1 */
\
(0x2 << 21))
/* UpdateRegs operation */
#define ZYNQ_NAND_ECC_CONFIG ((0x1 << 2) |
/* ECC available on APB */
\
(0x1 << 4) |
/* ECC read at end of page */
\
(0x0 << 5))
/* No Jumping */
#define ZYNQ_NAND_ECC_CMD1 ((0x80) |
/* Write command */
\
(0x00 << 8) |
/* Read command */
\
(0x30 << 16) |
/* Read End command */
\
(0x1 << 24))
/* Read End command calid */
#define ZYNQ_NAND_ECC_CMD2 ((0x85) |
/* Write col change cmd */
\
(0x05 << 8) |
/* Read col change cmd */
\
(0xE0 << 16) |
/* Read col change end cmd */
\
(0x1 << 24))
/* Read col change
end cmd valid */
/* AXI Address definitions */
#define START_CMD_SHIFT 3
#define END_CMD_SHIFT 11
#define END_CMD_VALID_SHIFT 20
#define ADDR_CYCLES_SHIFT 21
#define CLEAR_CS_SHIFT 21
#define ECC_LAST_SHIFT 10
#define COMMAND_PHASE (0 << 19)
#define DATA_PHASE (1 << 19)
#define ZYNQ_NAND_ECC_LAST (1 << ECC_LAST_SHIFT)
/* Set ECC_Last */
#define ZYNQ_NAND_CLEAR_CS (1 << CLEAR_CS_SHIFT)
/* Clear chip select */
/* ECC block registers bit position and bit mask */
#define ZYNQ_NAND_ECC_BUSY (1 << 6)
/* ECC block is busy */
#define ZYNQ_NAND_ECC_MASK 0x00FFFFFF
/* ECC value mask */
#define ZYNQ_NAND_ROW_ADDR_CYCL_MASK 0x0F
#define ZYNQ_NAND_COL_ADDR_CYCL_MASK 0xF0
/* NAND MIO buswidth count*/
#define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13
#define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8
/* Based on Fabian Gottlieb von Bellingshausen's work in Antarctica */
int
nand_spl_load_image
(
uint32_t
offs
,
unsigned
int
size
,
void
*
dst
)
extern
nand_info_t
nand_info
[
CONFIG_SYS_MAX_NAND_DEVICE
];
static
int
is_badblock
(
struct
mtd_info
*
mtd
,
loff_t
offs
,
int
allowbbt
)
{
register
struct
nand_chip
*
chip
=
mtd
->
priv
;
unsigned
int
block
=
offs
>>
chip
->
phys_erase_shift
;
unsigned
int
page
=
offs
>>
chip
->
page_shift
;
printf
(
" is_badblock(): offs=0x%08x block=%d page=%d
\n
"
,(
int
)
offs
,
block
,
page
);
//chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
//memset(chip->oob_poi, 0, mtd->oobsize);
//chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
//return chip->oob_poi[0] != 0xff;
return
0
;
}
/* nand_init() - initialize data to make nand usable by SPL */
void
nand_init
(
void
)
//dst or buf - destination in RAM
//offs - u-boot-dtb.img offset in NAND
//size - size of u-boot-dtb.img
int
nand_spl_load_image
(
uint32_t
offs
,
unsigned
int
size
,
void
*
buf
)
{
struct
nand_chip
*
chip
;
struct
mtd_info
*
mtd
;
unsigned
int
page
;
unsigned
int
nand_page_per_block
;
unsigned
int
sz
=
0
;
printf
(
"
\n
nand_spl_load_image(): offs=0x%08x size=%d (0x%08x) buf_addr=0x%08x
\n
"
,
offs
,
size
,
size
,
buf
);
udelay
(
10000
);
//if (mxs_nand_init()) return -ENODEV;
mtd
=
&
nand_info
[
0
];
//mtd.priv = &nand_chip;
chip
=
mtd
->
priv
;
page
=
offs
>>
chip
->
page_shift
;
nand_page_per_block
=
mtd
->
erasesize
/
mtd
->
writesize
;
debug
(
"%s offset:0x%08x len:%d page:%d
\n
"
,
__func__
,
offs
,
size
,
page
);
printf
(
" nand_page_per_block= %d
\n
"
,
nand_page_per_block
);
printf
(
" mtd->writesize= %d
\n
"
,
mtd
->
writesize
);
printf
(
" u-boot-dtb.img size is: %d (0x%08x)
\n
"
,
size
,
size
);
size
=
roundup
(
size
,
mtd
->
writesize
);
printf
(
" u-boot-dtb.img size after roundup is:%d
\n
"
,
size
);
//u32 testbuf[16];
while
(
sz
<
size
)
{
//if (mxs_read_page_ecc(&mtd, buf, page) < 0)
// return -1;
//printf(" Reading from NAND, offset:0x%08x page_index:%d to MEM address:0x%08x\n",offs, page, buf);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READ0
,
0
,
page
);
udelay
(
500
);
//read min
chip
->
read_buf
(
mtd
,
buf
,
min
(
size
-
sz
,
mtd
->
writesize
));
//chip->ecc.read_page(mtd, chip, buf, 0, page);
sz
+=
mtd
->
writesize
;
offs
+=
mtd
->
writesize
;
page
++
;
buf
+=
mtd
->
writesize
;
/*
* Check if we have crossed a block boundary, and if so
* check for bad block.
*/
//if (!(page % nand_page_per_block)) {
// /*
// * Yes, new block. See if this block is good. If not,
// * loop until we find a good block.
// */
// while (is_badblock(&mtd, offs, 1)) {
// page = page + nand_page_per_block;
// /* Check we've reached the end of flash. */
// if (page >= mtd->size >> chip->page_shift)
// return -ENOMEM;
// }
//}
}
return
0
;
}
/* already defined in nand.c
// nand_init() - initialize data to make nand usable by SPL
void nand_init(void)
{
puts("nand_init()\n");
udelay(5000);
board_nand_init();
}
*/
void
nand_init_custom
(
void
)
{
puts
(
"nand_init_custom()
\n
"
);
udelay
(
5000
);
//board_nand_init();
}
/* secret */
void
nand_deselect
(
void
)
{
puts
(
"nand_deselect(): empty function
\n
"
);
udelay
(
10000
);
}
void
nand_deselect2
(
void
)
{
printf
(
"nand_deselect2(): &nand_info[0]=0x%08x
\n
"
,(
u32
)
&
nand_info
[
0
]);
puts
(
"nand_deselect2(): empty function
\n
"
);
udelay
(
10000
);
}
u-boot-tree/drivers/mtd/nand/nand_base.c
0 → 100644
View file @
4bbaac41
This source diff could not be displayed because it is too large. You can
view the blob
instead.
u-boot-tree/drivers/mtd/nand/zynq_nand.c
View file @
4bbaac41
...
...
@@ -55,8 +55,8 @@
#define ZYNQ_NAND_ECC_CMD2 ((0x85) |
/* Write col change cmd */
\
(0x05 << 8) |
/* Read col change cmd */
\
(0xE0 << 16) |
/* Read col change end cmd */
\
(0x1 << 24))
/* Read col change
end cmd valid */
(0x1 << 24))
/* Read col change
end cmd valid */
/* AXI Address definitions */
#define START_CMD_SHIFT 3
#define END_CMD_SHIFT 11
...
...
@@ -773,6 +773,8 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
unsigned
long
end_cmd_valid
=
0
;
unsigned
long
i
;
//printf(" zynq_nand(): Command=0x%02x Column=0x%02x PageAddr=0x%08x\n",command,column,page_addr);
xnand
=
(
struct
zynq_nand_info
*
)
chip
->
priv
;
if
(
xnand
->
end_cmd_pending
)
{
/* Check for end command if this command request is same as the
...
...
@@ -905,6 +907,9 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
*/
static
void
zynq_nand_read_buf
(
struct
mtd_info
*
mtd
,
u8
*
buf
,
int
len
)
{
//printf("zynq_nand_read_buf():start len=0x%08x buf=0x%08x\n",len,buf);
struct
nand_chip
*
chip
=
mtd
->
priv
;
const
u32
*
nand
=
chip
->
IO_ADDR_R
;
...
...
@@ -955,6 +960,9 @@ static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
*/
static
void
zynq_nand_write_buf
(
struct
mtd_info
*
mtd
,
const
u8
*
buf
,
int
len
)
{
printf
(
"zynq_nand_write_buf(): len=%d buf=%d
\n
"
,
len
,
buf
);
struct
nand_chip
*
chip
=
mtd
->
priv
;
const
u32
*
nand
=
chip
->
IO_ADDR_W
;
...
...
@@ -1040,7 +1048,9 @@ static int zynq_nand_check_is_16bit_bw_flash(void)
(
mio_num_16bit
==
ZYNQ_NAND_MIO_NUM_NAND_16BIT
))
is_16bit_bw
=
NAND_BW_16BIT
;
return
is_16bit_bw
;
//return is_16bit_bw;
//elphel force 8 bits width
return
NAND_BW_8BIT
;
}
static
int
zynq_nand_init
(
struct
nand_chip
*
nand_chip
,
int
devnum
)
...
...
@@ -1056,7 +1066,12 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
int
ondie_ecc_enabled
=
0
;
int
is_16bit_bw
;
//printf("\n zynq_nand_init():start\n");
xnand
=
calloc
(
1
,
sizeof
(
struct
zynq_nand_info
));
//printf("ZYNQ_NAND_INIT: CALLOC @0x%08x size=%d\n",(u32)&xnand,sizeof(xnand));
if
(
!
xnand
)
{
printf
(
"%s: failed to allocate
\n
"
,
__func__
);
goto
free
;
...
...
@@ -1072,6 +1087,11 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
nand_chip
->
IO_ADDR_R
=
xnand
->
nand_base
;
nand_chip
->
IO_ADDR_W
=
xnand
->
nand_base
;
//printf(" ZYNQ_NAND_BASEADDR:0x%08x\n",(unsigned int)ZYNQ_NAND_BASEADDR);
//printf(" xnand->nand_base:0x%08x\n",(unsigned int)xnand->nand_base);
//printf(" nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
//printf(" nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);
/* Set the driver entry points for MTD */
nand_chip
->
cmdfunc
=
zynq_nand_cmd_function
;
nand_chip
->
dev_ready
=
zynq_nand_device_ready
;
...
...
@@ -1087,6 +1107,9 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
/* Check the NAND buswidth */
/* FIXME this will be changed by using NAND_BUSWIDTH_AUTO */
is_16bit_bw
=
zynq_nand_check_is_16bit_bw_flash
();
//printf(" is_16bit_bw: %d\n",is_16bit_bw);
if
(
is_16bit_bw
==
NAND_BW_UNKNOWN
)
{
printf
(
"%s: Unable detect NAND based on MIO settings
\n
"
,
__func__
);
...
...
@@ -1116,6 +1139,10 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
maf_id
=
nand_chip
->
read_byte
(
mtd
);
dev_id
=
nand_chip
->
read_byte
(
mtd
);
//printf(" maf_id=0x%02x dev_id=0x%02x\n",maf_id,dev_id);
//printf(" nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
//printf(" nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);
if
((
maf_id
==
0x2c
)
&&
((
dev_id
==
0xf1
)
||
(
dev_id
==
0xa1
)
||
(
dev_id
==
0xb1
)
||
(
dev_id
==
0xaa
)
||
(
dev_id
==
0xba
)
||
...
...
@@ -1146,6 +1173,13 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
}
if
(
ondie_ecc_enabled
)
{
//puts(" Welcome to OnDie ECC flash\n");
//printf(" ZYNQ_NAND_BASEADDR:0x%08x\n",(unsigned int)ZYNQ_NAND_BASEADDR);
//printf(" xnand->nand_base:0x%08x\n",(unsigned int)xnand->nand_base);
//printf(" nand_chip->IO_ADDR_R:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_R);
//printf(" nand_chip->IO_ADDR_W:0x%08x\n",(unsigned int)nand_chip->IO_ADDR_W);
/* bypass the controller ECC block */
ecc_cfg
=
readl
(
&
zynq_nand_smc_base
->
emcr
);
ecc_cfg
&=
~
0xc
;
...
...
@@ -1206,6 +1240,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
&
zynq_nand_smc_base
->
emcr
);
break
;
case
2048
:
printf
(
" necc_page_size = 0x3
\n
"
);
ecc_page_size
=
0x3
;
/* Set the ECC memory config register */
writel
((
ZYNQ_NAND_ECC_CONFIG
|
ecc_page_size
),
...
...
@@ -1248,6 +1283,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
if
(
nand_register
(
devnum
))
goto
fail
;
//printf(" zynq_nand_init(): end\n");
return
0
;
fail:
free:
...
...
@@ -1261,6 +1297,9 @@ void board_nand_init(void)
{
struct
nand_chip
*
nand
=
&
nand_chip
[
0
];
printf
(
"board_nand_init(): &nand_chip[0]=0x%08x
\n
"
,(
u32
)
&
nand_chip
[
0
]);
if
(
zynq_nand_init
(
nand
,
0
))
puts
(
"ZYNQ NAND init failed
\n
"
);
}
u-boot-tree/include/configs/elphel393.h
View file @
4bbaac41
...
...
@@ -32,7 +32,7 @@
#define CONFIG_NAND_ZYNQ
#ifdef CONFIG_NAND_ZYNQ
#define CONFIG_CMD_NAND
/*#define CONFIG_CMD_NAND*/
#define CONFIG_CMD_NAND_LOCK_UNLOCK
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_SELF_INIT
...
...
@@ -40,15 +40,35 @@
#define CONFIG_MTD_DEVICE
#endif
#define CONFIG_SPL_NAND_ELPHEL393
#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x40000
/*
#define CONFIG_SPL_NAND_LOAD
#define CONFIG_SYS_NAND_U_BOOT_SIZE 0x100000
#define CONFIG_SYS_NAND_U_BOOT_DST 0x0
#define CONFIG_SYS_NAND_U_BOOT_START 0x0
*/
#define CONFIG_SPL_NAND_SUPPORT
#define CONFIG_SPL_NAND_DRIVERS
*/
#define CONFIG_SPL_NAND_INIT
#define CONFIG_SPL_NAND_BASE
#define CONFIG_SPL_NAND_ECC
#define CONFIG_SPL_NAND_BBT
#define CONFIG_SPL_NAND_IDS
/* Load U-Boot to this address */
#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_NAND_U_BOOT_DST
#define CONFIG_MTD
/*#define CONFIG_DEFAULT_DEVICE_TREE elphel393*/
/*redefined in zynq-common.h*/
#undef CONFIG_CMD_NAND
/*#undef CONFIG_CMD_NAND*/
#include <configs/zynq-common.h>
#undef CONFIG_SYS_PROMPT
...
...
@@ -57,22 +77,12 @@
/*skip u-boot falcon mode*/
#undef CONFIG_SPL_OS_BOOT
#undef CONFIG_DISPLAY_BOARDINFO
#include <configs/ezynq/ezynq_MT41K256M16HA107.h>
/* should be before zed_ezynq.h as it overwrites DDR3L with DDR3 */
#include <configs/ezynq/ezynq_XC7Z030_1FBG484C.h>
#include <configs/ezynq/ezynq_elphel393.h>
/*#define CONFIG_SYS_MAX_NAND_DEVICE 1*/
/*#define CONFIG_SYS_NAND_BASE 0xE1000000*/
/*
#define CONFIG_SPL_NAND_DENALI
#define CONFIG_SYS_NAND_DATA_BASE 0xE1000000
#define CONFIG_SYS_NAND_REGS_BASE 0xE1000000
#define CONFIG_SYS_NAND_BAD_BLOCK_POS 0
*/
/*
#define CONFIG_SYS_NAND_U_BOOT_OFFS 0xE1000000
*/
#define CONFIG_CMD_MEMTEST
#define CONFIG_BOOTDELAY 1
/* -1 to Disable autoboot */
...
...
@@ -92,8 +102,8 @@
"loadbit_addr=0x100000\0" \
"loadbootenv_addr=0x2000000\0" \
"kernel_size=0x500000\0" \
"devicetree_size=0x
2
0000\0" \
"ramdisk_size=0x
5E
0000\0" \
"devicetree_size=0x
10
0000\0" \
"ramdisk_size=0x
1E0
0000\0" \
"boot_size=0xF00000\0" \
"fdt_high=0x20000000\0" \
"initrd_high=0x20000000\0" \
...
...
@@ -144,11 +154,11 @@
"bootm 0x3000000 0x2000000 0x2A00000; " \
"fi\0" \
"nandboot=echo Copying Linux from NAND flash to RAM... && " \
"nand read 0x3
000000 0x10
0000 ${kernel_size} && " \
"nand read 0x
2A00000 0x60
0000 ${devicetree_size} && " \
"nand read 0x3
F00000 0x24
0000 ${kernel_size} && " \
"nand read 0x
3E00000 0x14
0000 ${devicetree_size} && " \
"echo Copying ramdisk... && " \
"nand read 0x2000000 0x
62
0000 ${ramdisk_size} && " \
"bootm 0x3
000000 0x2000000 0x2A
00000\0" \
"nand read 0x2000000 0x
124
0000 ${ramdisk_size} && " \
"bootm 0x3
F00000 0x2000000 0x3E
00000\0" \
"jtagboot=echo TFTPing Linux to RAM... && " \
"tftpboot 0x3000000 ${kernel_image} && " \
"tftpboot 0x2A00000 ${devicetree_image} && " \
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment