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
9 years ago
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
);
}
...
...
This diff is collapsed.
Click to expand it.
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
...
...
This diff is collapsed.
Click to expand it.
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
);
}
This diff is collapsed.
Click to expand it.
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.
This diff is collapsed.
Click to expand it.
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
"
);
}
This diff is collapsed.
Click to expand it.
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} && " \
...
...
This diff is collapsed.
Click to expand it.
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