Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
duo-buildroot-sdk
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
duo-buildroot-sdk
Commits
7f048482
Commit
7f048482
authored
Oct 19, 2023
by
carbon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
buildroot: add duo-pinmux
parent
0c1ee95d
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
518 additions
and
0 deletions
+518
-0
buildroot-2021.05/configs/milkv_duo_musl_riscv64_defconfig
buildroot-2021.05/configs/milkv_duo_musl_riscv64_defconfig
+1
-0
buildroot-2021.05/package/Config.in
buildroot-2021.05/package/Config.in
+1
-0
buildroot-2021.05/package/duo-pinmux/Config.in
buildroot-2021.05/package/duo-pinmux/Config.in
+4
-0
buildroot-2021.05/package/duo-pinmux/duo-pinmux.mk
buildroot-2021.05/package/duo-pinmux/duo-pinmux.mk
+14
-0
buildroot-2021.05/package/duo-pinmux/src/devmem.c
buildroot-2021.05/package/duo-pinmux/src/devmem.c
+105
-0
buildroot-2021.05/package/duo-pinmux/src/devmem.h
buildroot-2021.05/package/duo-pinmux/src/devmem.h
+12
-0
buildroot-2021.05/package/duo-pinmux/src/duo_pinmux.c
buildroot-2021.05/package/duo-pinmux/src/duo_pinmux.c
+193
-0
buildroot-2021.05/package/duo-pinmux/src/func.h
buildroot-2021.05/package/duo-pinmux/src/func.h
+188
-0
No files found.
buildroot-2021.05/configs/milkv_duo_musl_riscv64_defconfig
View file @
7f048482
...
@@ -269,6 +269,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES=""
...
@@ -269,6 +269,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES=""
# BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES is not set
# BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES is not set
# BR2_PACKAGE_BUSYBOX_WATCHDOG is not set
# BR2_PACKAGE_BUSYBOX_WATCHDOG is not set
BR2_PACKAGE_WIRINGX=y
BR2_PACKAGE_WIRINGX=y
BR2_PACKAGE_DUO_PINMUX=y
BR2_PACKAGE_SKELETON=y
BR2_PACKAGE_SKELETON=y
BR2_PACKAGE_HAS_SKELETON=y
BR2_PACKAGE_HAS_SKELETON=y
BR2_PACKAGE_PROVIDES_SKELETON="skeleton-init-sysv"
BR2_PACKAGE_PROVIDES_SKELETON="skeleton-init-sysv"
...
...
buildroot-2021.05/package/Config.in
View file @
7f048482
...
@@ -2,6 +2,7 @@ menu "Target packages"
...
@@ -2,6 +2,7 @@ menu "Target packages"
source "package/busybox/Config.in"
source "package/busybox/Config.in"
source "package/wiringx/Config.in"
source "package/wiringx/Config.in"
source "package/duo-pinmux/Config.in"
source "package/skeleton/Config.in"
source "package/skeleton/Config.in"
source "package/skeleton-custom/Config.in"
source "package/skeleton-custom/Config.in"
source "package/skeleton-init-common/Config.in"
source "package/skeleton-init-common/Config.in"
...
...
buildroot-2021.05/package/duo-pinmux/Config.in
0 → 100644
View file @
7f048482
config BR2_PACKAGE_DUO_PINMUX
bool "Duo pinmux"
help
Pinmux for Milk-V Duo
buildroot-2021.05/package/duo-pinmux/duo-pinmux.mk
0 → 100644
View file @
7f048482
DUO_PINMUX_SITE
=
$(TOPDIR)
/package/duo-pinmux/src
DUO_PINMUX_VERSION
=
1.0.0
DUO_PINMUX_SITE_METHOD
=
local
define
DUO_PINMUX_BUILD_CMDS
$(TARGET_MAKE_ENV)
$(TARGET_CC)
$(TARGET_CFLAGS)
$(TARGET_LDFLAGS)
\
$(@D)/*.c
-o
$(@D)/duo-pinmux
endef
define
DUO_PINMUX_INSTALL_TARGET_CMDS
$(INSTALL)
-D
-m
0755
$(@D)/duo-pinmux
$(TARGET_DIR)/usr/bin/
endef
$(eval
$(generic-package))
buildroot-2021.05/package/duo-pinmux/src/devmem.c
0 → 100644
View file @
7f048482
/*
** read/write phy addr in userspace
** open /dev/mem
** taiqiang.cao@bitmain.com
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include "devmem.h"
// DEBUG_SET_LEVEL(DEBUG_LEVEL_ERR);
#define ERR printf
#define DEBUG printf
static
int
devmem_fd
;
void
*
devm_map
(
unsigned
long
addr
,
int
len
)
{
off_t
offset
;
void
*
map_base
;
devmem_fd
=
open
(
"/dev/mem"
,
O_RDWR
|
O_SYNC
);
if
(
devmem_fd
==
-
1
)
{
ERR
(
"cannot open '/dev/mem'
\n
"
);
goto
open_err
;
}
// DEBUG("/dev/mem opened.\n");
offset
=
addr
&
~
(
sysconf
(
_SC_PAGE_SIZE
)
-
1
);
map_base
=
mmap
(
NULL
,
len
+
addr
-
offset
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
devmem_fd
,
offset
);
if
(
map_base
==
MAP_FAILED
)
{
ERR
(
"mmap failed
\n
"
);
goto
mmap_err
;
}
// DEBUG("Memory mapped at address %p.\n", map_base + addr - offset);
return
map_base
+
addr
-
offset
;
mmap_err:
close
(
devmem_fd
);
open_err:
return
NULL
;
}
void
devm_unmap
(
void
*
virt_addr
,
int
len
)
{
unsigned
long
addr
;
if
(
devmem_fd
==
-
1
)
{
ERR
(
"'/dev/mem' is closed
\n
"
);
return
;
}
/* page align */
addr
=
(((
unsigned
long
)
virt_addr
)
&
~
(
sysconf
(
_SC_PAGE_SIZE
)
-
1
));
munmap
((
void
*
)
addr
,
len
+
(
unsigned
long
)
virt_addr
-
addr
);
close
(
devmem_fd
);
}
/* read/write 32bit data*/
uint32_t
devmem_readl
(
unsigned
long
addr
)
{
uint32_t
val
;
void
*
virt_addr
;
virt_addr
=
devm_map
(
addr
,
4
);
if
(
virt_addr
==
NULL
)
{
ERR
(
"readl addr map failed
\n
"
);
return
0
;
}
val
=
*
(
uint32_t
*
)
virt_addr
;
devm_unmap
(
virt_addr
,
4
);
return
val
;
}
void
devmem_writel
(
unsigned
long
addr
,
uint32_t
val
)
{
void
*
virt_addr
;
virt_addr
=
devm_map
(
addr
,
4
);
if
(
virt_addr
==
NULL
)
{
ERR
(
"writel addr map failed
\n
"
);
return
;
}
*
(
uint32_t
*
)
virt_addr
=
val
;
devm_unmap
(
virt_addr
,
4
);
}
buildroot-2021.05/package/duo-pinmux/src/devmem.h
0 → 100644
View file @
7f048482
#ifndef _DEVMEM_H_
#define _DEVMEM_H_
#include <stdint.h>
void
*
devm_map
(
unsigned
long
addr
,
int
len
);
void
devm_unmap
(
void
*
virt_addr
,
int
len
);
uint32_t
devmem_readl
(
unsigned
long
addr
);
void
devmem_writel
(
unsigned
long
addr
,
uint32_t
val
);
#endif
buildroot-2021.05/package/duo-pinmux/src/duo_pinmux.c
0 → 100644
View file @
7f048482
#include "devmem.h"
#include "func.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
#define PINMUX_BASE 0x03001000
#define INVALID_PIN 9999
struct
pinlist
{
char
name
[
32
];
uint32_t
offset
;
}
pinlist_st
;
struct
pinlist
cv180x_pin
[]
=
{
{
"GP0"
,
0x4c
},
// IIC0_SCL
{
"GP1"
,
0x50
},
// IIC0_SDA
{
"GP2"
,
0x84
},
// SD1_GPIO1
{
"GP3"
,
0x88
},
// SD1_GPIO0
{
"GP4"
,
0x90
},
// SD1_D2
{
"GP5"
,
0x94
},
// SD1_D1
{
"GP6"
,
0xa0
},
// SD1_CLK
{
"GP7"
,
0x9c
},
// SD1_CMD
{
"GP8"
,
0x98
},
// SD1_D0
{
"GP9"
,
0x8c
},
// SD1_D3
{
"GP10"
,
0xf0
},
// PAD_MIPIRX1P
{
"GP11"
,
0xf4
},
// PAD_MIPIRX0N
{
"GP12"
,
0x24
},
// UART0_TX
{
"GP13"
,
0x28
},
// UART0_RX
{
"GP14"
,
0x1c
},
// SD0_PWR_EN
{
"GP15"
,
0x20
},
// SPK_EN
{
"GP16"
,
0x3c
},
// SPINOR_MISO
{
"GP17"
,
0x40
},
// SPINOR_CS_X
{
"GP18"
,
0x30
},
// SPINOR_SCK
{
"GP19"
,
0x34
},
// SPINOR_MOSI
{
"GP20"
,
0x38
},
// SPINOR_WP_X
{
"GP21"
,
0x2c
},
// SPINOR_HOLD_X
{
"GP22"
,
0x68
},
// PWR_SEQ2
{
"GP26"
,
0xa8
},
// ADC1
{
"GP27"
,
0xac
},
// USB_VBUS_DET
{
"GP25"
,
0x12c
},
// PAD_AUD_AOUTR
};
uint32_t
convert_func_to_value
(
char
*
pin
,
char
*
func
)
{
uint32_t
i
=
0
;
uint32_t
max_fun_num
=
NELEMS
(
cv180x_pin_func
);
char
v
;
for
(
i
=
0
;
i
<
max_fun_num
;
i
++
)
{
if
(
strcmp
(
cv180x_pin_func
[
i
].
func
,
func
)
==
0
)
{
if
(
strncmp
(
cv180x_pin_func
[
i
].
name
,
pin
,
strlen
(
pin
))
==
0
)
{
v
=
cv180x_pin_func
[
i
].
name
[
strlen
(
cv180x_pin_func
[
i
].
name
)
-
1
];
break
;
}
}
}
if
(
i
==
max_fun_num
)
{
printf
(
"ERROR: invalid pin or func
\n
"
);
return
INVALID_PIN
;
}
return
(
v
-
0x30
);
}
void
print_fun
(
char
*
name
,
uint32_t
value
)
{
uint32_t
i
=
0
;
uint32_t
max_fun_num
=
NELEMS
(
cv180x_pin_func
);
char
pinname
[
128
];
sprintf
(
pinname
,
"%s%d"
,
name
,
value
);
printf
(
"%s function:
\n
"
,
name
);
for
(
i
=
0
;
i
<
max_fun_num
;
i
++
)
{
if
(
strlen
(
cv180x_pin_func
[
i
].
name
)
!=
(
strlen
(
name
)
+
1
))
{
continue
;
}
if
(
strncmp
(
pinname
,
cv180x_pin_func
[
i
].
name
,
strlen
(
name
))
==
0
)
{
if
(
strcmp
(
pinname
,
cv180x_pin_func
[
i
].
name
)
==
0
)
printf
(
"[v] %s
\n
"
,
cv180x_pin_func
[
i
].
func
);
else
printf
(
"[ ] %s
\n
"
,
cv180x_pin_func
[
i
].
func
);
// break;
}
}
printf
(
"
\n
"
);
}
void
print_usage
(
const
char
*
prog
)
{
printf
(
"pinmux for duo
\n
"
);
printf
(
"%s -p <== List all pins
\n
"
,
prog
);
printf
(
"%s -l <== List all pins and its func
\n
"
,
prog
);
printf
(
"%s -r pin <== Get func from pin
\n
"
,
prog
);
printf
(
"%s -w pin/func <== Set func to pin
\n
"
,
prog
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
int
opt
=
0
;
uint32_t
i
=
0
;
uint32_t
value
;
char
pin
[
32
];
char
func
[
32
];
uint32_t
f_val
;
if
(
argc
==
1
)
{
print_usage
(
argv
[
0
]);
return
1
;
}
while
((
opt
=
getopt
(
argc
,
argv
,
"hplr:w:"
))
!=
-
1
)
{
switch
(
opt
)
{
case
'r'
:
for
(
i
=
0
;
i
<
NELEMS
(
cv180x_pin
);
i
++
)
{
if
(
strcmp
(
optarg
,
cv180x_pin
[
i
].
name
)
==
0
)
break
;
}
if
(
i
!=
NELEMS
(
cv180x_pin
))
{
value
=
devmem_readl
(
PINMUX_BASE
+
cv180x_pin
[
i
].
offset
);
// printf("value %d\n", value);
print_fun
(
optarg
,
value
);
printf
(
"register: 0x%x
\n
"
,
PINMUX_BASE
+
cv180x_pin
[
i
].
offset
);
printf
(
"value: %d
\n
"
,
value
);
}
else
{
printf
(
"
\n
Invalid option: %s"
,
optarg
);
}
break
;
case
'w'
:
// printf("optarg %s\n", optarg);
if
(
sscanf
(
optarg
,
"%[^/]/%s"
,
pin
,
func
)
!=
2
)
print_usage
(
argv
[
0
]);
printf
(
"pin %s
\n
"
,
pin
);
printf
(
"func %s
\n
"
,
func
);
for
(
i
=
0
;
i
<
NELEMS
(
cv180x_pin
);
i
++
)
{
if
(
strcmp
(
pin
,
cv180x_pin
[
i
].
name
)
==
0
)
break
;
}
if
(
i
!=
NELEMS
(
cv180x_pin
))
{
f_val
=
convert_func_to_value
(
pin
,
func
);
if
(
f_val
==
INVALID_PIN
)
return
1
;
devmem_writel
(
PINMUX_BASE
+
cv180x_pin
[
i
].
offset
,
f_val
);
printf
(
"register: %x
\n
"
,
PINMUX_BASE
+
cv180x_pin
[
i
].
offset
);
printf
(
"value: %d
\n
"
,
f_val
);
// printf("value %d\n", value);
}
else
{
printf
(
"
\n
Invalid option: %s
\n
"
,
optarg
);
}
break
;
case
'p'
:
printf
(
"Pinlist:
\n
"
);
for
(
i
=
0
;
i
<
NELEMS
(
cv180x_pin
);
i
++
)
printf
(
"%s
\n
"
,
cv180x_pin
[
i
].
name
);
break
;
case
'l'
:
for
(
i
=
0
;
i
<
NELEMS
(
cv180x_pin
);
i
++
)
{
value
=
devmem_readl
(
PINMUX_BASE
+
cv180x_pin
[
i
].
offset
);
// printf("value %d\n", value);
print_fun
(
cv180x_pin
[
i
].
name
,
value
);
}
break
;
case
'h'
:
print_usage
(
argv
[
0
]);
break
;
case
'?'
:
print_usage
(
argv
[
0
]);
break
;
default:
print_usage
(
argv
[
0
]);
break
;
}
}
return
0
;
}
buildroot-2021.05/package/duo-pinmux/src/func.h
0 → 100644
View file @
7f048482
struct
funlist
{
char
name
[
32
];
char
func
[
32
];
}
funlist_st
;
struct
funlist
cv180x_pin_func
[]
=
{
// GP0 IIC0_SCL
{
"GP00"
,
"JTAG_TDI"
},
{
"GP01"
,
"UART1_TX"
},
{
"GP02"
,
"UART2_TX"
},
{
"GP03"
,
"GP0"
},
{
"GP04"
,
"IIC0_SCL"
},
{
"GP05"
,
"WG0_D0"
},
{
"GP07"
,
"DBG_10"
},
// GP1 IIC0_SDA
{
"GP10"
,
"JTAG_TDO"
},
{
"GP11"
,
"UART1_RX"
},
{
"GP12"
,
"UART2_RX"
},
{
"GP13"
,
"GP1"
},
{
"GP14"
,
"IIC0_SDA"
},
{
"GP15"
,
"WG0_D1"
},
{
"GP16"
,
"WG1_D0"
},
{
"GP17"
,
"DBG_11"
},
// GP2 SD1_GPIO1
{
"GP21"
,
"UART4_TX"
},
{
"GP23"
,
"GP2"
},
{
"GP27"
,
"PWM_10"
},
// GP3 SD1_GPIO0
{
"GP31"
,
"UART4_RX"
},
{
"GP33"
,
"GP3"
},
{
"GP37"
,
"PWM_11"
},
// GP4 SD1_D2
{
"GP40"
,
"PWR_SD1_D2"
},
{
"GP41"
,
"IIC1_SCL"
},
{
"GP42"
,
"UART2_TX"
},
{
"GP43"
,
"GP4"
},
{
"GP44"
,
"CAM_MCLK0"
},
{
"GP45"
,
"UART3_TX"
},
{
"GP46"
,
"PWR_SPINOR1_HOLD_X"
},
{
"GP47"
,
"PWM_5"
},
// GP5 SD1_D1
{
"GP50"
,
"PWR_SD1_D1"
},
{
"GP51"
,
"IIC1_SDA"
},
{
"GP52"
,
"UART2_RX"
},
{
"GP53"
,
"GP5"
},
{
"GP54"
,
"CAM_MCLK1"
},
{
"GP55"
,
"UART3_RX"
},
{
"GP56"
,
"PWR_SPINOR1_WP_X"
},
{
"GP57"
,
"PWM_6"
},
// GP6 SD1_CLK
{
"GP60"
,
"PWR_SD1_CLK"
},
{
"GP61"
,
"SPI2_SCK"
},
{
"GP62"
,
"IIC3_SDA"
},
{
"GP63"
,
"GP6"
},
{
"GP64"
,
"CAM_HS0"
},
{
"GP65"
,
"EPHY_SPD_LED"
},
{
"GP66"
,
"PWR_SPINOR1_SCK"
},
{
"GP67"
,
"PWM_9"
},
// GP7 SD1_CMD
{
"GP70"
,
"PWR_SD1_CMD"
},
{
"GP71"
,
"SPI2_SDO"
},
{
"GP72"
,
"IIC3_SCL"
},
{
"GP73"
,
"GP7"
},
{
"GP74"
,
"CAM_VS0"
},
{
"GP75"
,
"EPHY_LNK_LED"
},
{
"GP76"
,
"PWR_SPINOR1_MOSI"
},
{
"GP77"
,
"PWM_8"
},
// GP8 SD1_D0
{
"GP80"
,
"PWR_SD1_D0"
},
{
"GP81"
,
"SPI2_SDI"
},
{
"GP82"
,
"IIC1_SDA"
},
{
"GP83"
,
"GP8"
},
{
"GP84"
,
"CAM_MCLK1"
},
{
"GP85"
,
"UART3_RTS"
},
{
"GP86"
,
"PWR_SPINOR1_MISO"
},
{
"GP87"
,
"PWM_7"
},
// GP9 SD1_D3
{
"GP90"
,
"PWR_SD1_D3"
},
{
"GP91"
,
"SPI2_CS_X"
},
{
"GP92"
,
"IIC1_SCL"
},
{
"GP93"
,
"GP9"
},
{
"GP94"
,
"CAM_MCLK0"
},
{
"GP95"
,
"UART3_CTS"
},
{
"GP96"
,
"PWR_SPINOR1_CS_X"
},
{
"GP97"
,
"PWM_4"
},
// GP10 PAD_MIPIRX1P
{
"GP101"
,
"VI0_D_6"
},
{
"GP103"
,
"GP10"
},
{
"GP104"
,
"IIC1_SDA"
},
{
"GP106"
,
"KEY_ROW2"
},
{
"GP107"
,
"DBG_9"
},
// GP11 PAD_MIPIRX0N
{
"GP111"
,
"VI0_D_7"
},
{
"GP113"
,
"GP11"
},
{
"GP114"
,
"IIC1_SCL"
},
{
"GP115"
,
"CAM_MCLK1"
},
{
"GP117"
,
"DBG_10"
},
// GP12 UART0_TX
{
"GP120"
,
"UART0_TX"
},
{
"GP121"
,
"CAM_MCLK1"
},
{
"GP122"
,
"PWM_4"
},
{
"GP123"
,
"GP12"
},
{
"GP124"
,
"UART1_TX"
},
{
"GP125"
,
"AUX1"
},
{
"GP126"
,
"JTAG_TMS"
},
{
"GP127"
,
"DBG_6"
},
// GP13 UART0_RX
{
"GP130"
,
"UART0_RX"
},
{
"GP131"
,
"CAM_MCLK0"
},
{
"GP132"
,
"PWM_5"
},
{
"GP133"
,
"GP13"
},
{
"GP134"
,
"UART1_RX"
},
{
"GP135"
,
"AUX0"
},
{
"GP136"
,
"JTAG_TCK"
},
{
"GP137"
,
"DBG_7"
},
// GP14 SD0_PWR_EN
{
"GP140"
,
"SDIO0_PWR_EN"
},
{
"GP143"
,
"GP14"
},
// GP15 SPK_EN
{
"GP153"
,
"GP15"
},
// GP16 SPINOR_MISO
{
"GP161"
,
"SPINOR_MISO"
},
{
"GP162"
,
"SPINAND_MISO"
},
{
"GP163"
,
"GP16"
},
// GP17 SPINOR_CS_X
{
"GP171"
,
"SPINOR_CS_X"
},
{
"GP172"
,
"SPINAND_CS"
},
{
"GP173"
,
"GP17"
},
// GP18 SPINOR_SCK
{
"GP181"
,
"SPINOR_SCK"
},
{
"GP182"
,
"SPINAND_CLK"
},
{
"GP183"
,
"GP18"
},
// GP19 SPINOR_MOSI
{
"GP191"
,
"SPINOR_MOSI"
},
{
"GP192"
,
"SPINAND_MOSI"
},
{
"GP193"
,
"GP19"
},
// GP20 SPINOR_WP_X
{
"GP201"
,
"SPINOR_WP_X"
},
{
"GP202"
,
"SPINAND_WP"
},
{
"GP203"
,
"GP20"
},
// GP21 SPINOR_HOLD_X
{
"GP211"
,
"SPINOR_HOLD_X"
},
{
"GP212"
,
"SPINAND_HOLD"
},
{
"GP213"
,
"GP21"
},
// GP22 PWR_SEQ2
{
"GP220"
,
"PWR_SEQ2"
},
{
"GP223"
,
"GP22"
},
// GP25 PAD_AUD_AOUTR
{
"GP253"
,
"GP25"
},
{
"GP254"
,
"IIS1_DI"
},
{
"GP255"
,
"IIS2_DO"
},
{
"GP256"
,
"IIS1_DO"
},
// GP26 ADC1
{
"GP263"
,
"GP26"
},
{
"GP264"
,
"KEY_COL2"
},
{
"GP266"
,
"PWM_3"
},
// GP27 USB_VBUS_DET
{
"GP270"
,
"USB_VBUS_DET"
},
{
"GP273"
,
"GP27"
},
{
"GP274"
,
"CAM_MCLK0"
},
{
"GP275"
,
"CAM_MCLK1"
},
{
"GP276"
,
"PWM_4"
},
};
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