Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
OpenBMC Firmware
talos-obmc-linux
Commits
1a55361e
Commit
1a55361e
authored
11 years ago
by
Lee Jones
Browse files
Options
Download
Plain Diff
Merge branch 'ib-mfd-omap' into HEAD
parents
507792c9
2e1b365c
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
136 additions
and
114 deletions
+136
-114
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+23
-0
Documentation/devicetree/bindings/mfd/omap-usb-tll.txt
Documentation/devicetree/bindings/mfd/omap-usb-tll.txt
+10
-0
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap4.dtsi
+6
-0
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/omap5.dtsi
+6
-0
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/cclock3xxx_data.c
+0
-4
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+0
-6
drivers/clk/ti/clk-3xxx.c
drivers/clk/ti/clk-3xxx.c
+0
-4
drivers/mfd/omap-usb-host.c
drivers/mfd/omap-usb-host.c
+90
-99
drivers/mfd/omap-usb-tll.c
drivers/mfd/omap-usb-tll.c
+1
-1
No files found.
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
View file @
1a55361e
...
...
@@ -32,6 +32,29 @@ Optional properties:
- single-ulpi-bypass: Must be present if the controller contains a single
ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
clock-names.
- clock-names: should include:
For OMAP3
* "usbhost_120m_fck" - 120MHz Functional clock.
For OMAP4+
* "refclk_60m_int" - 60MHz internal reference clock for UTMI clock mux
* "refclk_60m_ext_p1" - 60MHz external ref. clock for Port 1's UTMI clock mux.
* "refclk_60m_ext_p2" - 60MHz external ref. clock for Port 2's UTMI clock mux
* "utmi_p1_gfclk" - Port 1 UTMI clock mux.
* "utmi_p2_gfclk" - Port 2 UTMI clock mux.
* "usb_host_hs_utmi_p1_clk" - Port 1 UTMI clock gate.
* "usb_host_hs_utmi_p2_clk" - Port 2 UTMI clock gate.
* "usb_host_hs_utmi_p3_clk" - Port 3 UTMI clock gate.
* "usb_host_hs_hsic480m_p1_clk" - Port 1 480MHz HSIC clock gate.
* "usb_host_hs_hsic480m_p2_clk" - Port 2 480MHz HSIC clock gate.
* "usb_host_hs_hsic480m_p3_clk" - Port 3 480MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p1_clk" - Port 1 60MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p2_clk" - Port 2 60MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p3_clk" - Port 3 60MHz HSIC clock gate.
Required properties if child node exists:
- #address-cells: Must be 1
...
...
This diff is collapsed.
Click to expand it.
Documentation/devicetree/bindings/mfd/omap-usb-tll.txt
View file @
1a55361e
...
...
@@ -7,6 +7,16 @@ Required properties:
- interrupts : should contain the TLL module's interrupt
- ti,hwmod : must contain "usb_tll_hs"
Optional properties:
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
clock-names.
- clock-names: should include:
* "usb_tll_hs_usb_ch0_clk" - USB TLL channel 0 clock
* "usb_tll_hs_usb_ch1_clk" - USB TLL channel 1 clock
* "usb_tll_hs_usb_ch2_clk" - USB TLL channel 2 clock
Example:
usbhstll: usbhstll@4a062000 {
...
...
This diff is collapsed.
Click to expand it.
arch/arm/boot/dts/omap4.dtsi
View file @
1a55361e
...
...
@@ -697,6 +697,12 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&init_60m_fclk>,
<&xclk60mhsp1_ck>,
<&xclk60mhsp2_ck>;
clock-names = "refclk_60m_int",
"refclk_60m_ext_p1",
"refclk_60m_ext_p2";
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3", "usb-ohci";
...
...
This diff is collapsed.
Click to expand it.
arch/arm/boot/dts/omap5.dtsi
View file @
1a55361e
...
...
@@ -775,6 +775,12 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&l3init_60m_fclk>,
<&xclk60mhsp1_ck>,
<&xclk60mhsp2_ck>;
clock-names = "refclk_60m_int",
"refclk_60m_ext_p1",
"refclk_60m_ext_p2";
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3", "usb-ohci";
...
...
This diff is collapsed.
Click to expand it.
arch/arm/mach-omap2/cclock3xxx_data.c
View file @
1a55361e
...
...
@@ -3495,10 +3495,6 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "dss_tv_fck", &dss_tv_fck),
CLK(NULL, "dss_96m_fck", &dss_96m_fck),
CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
CLK
(
NULL
,
"utmi_p1_gfclk"
,
&
dummy_ck
),
CLK
(
NULL
,
"utmi_p2_gfclk"
,
&
dummy_ck
),
CLK
(
NULL
,
"xclk60mhsp1_ck"
,
&
dummy_ck
),
CLK
(
NULL
,
"xclk60mhsp2_ck"
,
&
dummy_ck
),
CLK(NULL, "init_60m_fclk", &dummy_ck),
CLK(NULL, "gpt1_fck", &gpt1_fck),
CLK(NULL, "aes2_ick", &aes2_ick),
...
...
This diff is collapsed.
Click to expand it.
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
View file @
1a55361e
...
...
@@ -1955,10 +1955,6 @@ static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
.
sysc
=
&
omap3xxx_usb_host_hs_sysc
,
};
static
struct
omap_hwmod_opt_clk
omap3xxx_usb_host_hs_opt_clks
[]
=
{
{
.
role
=
"ehci_logic_fck"
,
.
clk
=
"usbhost_120m_fck"
,
},
};
static
struct
omap_hwmod_irq_info
omap3xxx_usb_host_hs_irqs
[]
=
{
{
.
name
=
"ohci-irq"
,
.
irq
=
76
+
OMAP_INTC_START
,
},
{
.
name
=
"ehci-irq"
,
.
irq
=
77
+
OMAP_INTC_START
,
},
...
...
@@ -1981,8 +1977,6 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
.
idlest_stdby_bit
=
OMAP3430ES2_ST_USBHOST_STDBY_SHIFT
,
},
},
.
opt_clks
=
omap3xxx_usb_host_hs_opt_clks
,
.
opt_clks_cnt
=
ARRAY_SIZE
(
omap3xxx_usb_host_hs_opt_clks
),
/*
* Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
...
...
This diff is collapsed.
Click to expand it.
drivers/clk/ti/clk-3xxx.c
View file @
1a55361e
...
...
@@ -130,10 +130,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK
(
NULL
,
"dss_tv_fck"
,
"dss_tv_fck"
),
DT_CLK
(
NULL
,
"dss_96m_fck"
,
"dss_96m_fck"
),
DT_CLK
(
NULL
,
"dss2_alwon_fck"
,
"dss2_alwon_fck"
),
DT_CLK
(
NULL
,
"utmi_p1_gfclk"
,
"dummy_ck"
),
DT_CLK
(
NULL
,
"utmi_p2_gfclk"
,
"dummy_ck"
),
DT_CLK
(
NULL
,
"xclk60mhsp1_ck"
,
"dummy_ck"
),
DT_CLK
(
NULL
,
"xclk60mhsp2_ck"
,
"dummy_ck"
),
DT_CLK
(
NULL
,
"init_60m_fclk"
,
"dummy_ck"
),
DT_CLK
(
NULL
,
"gpt1_fck"
,
"gpt1_fck"
),
DT_CLK
(
NULL
,
"aes2_ick"
,
"aes2_ick"
),
...
...
This diff is collapsed.
Click to expand it.
drivers/mfd/omap-usb-host.c
View file @
1a55361e
...
...
@@ -665,55 +665,78 @@ static int usbhs_omap_probe(struct platform_device *pdev)
goto
err_mem
;
}
need_logic_fck
=
false
;
/* Set all clocks as invalid to begin with */
omap
->
ehci_logic_fck
=
ERR_PTR
(
-
ENODEV
);
omap
->
init_60m_fclk
=
ERR_PTR
(
-
ENODEV
);
omap
->
utmi_p1_gfclk
=
ERR_PTR
(
-
ENODEV
);
omap
->
utmi_p2_gfclk
=
ERR_PTR
(
-
ENODEV
);
omap
->
xclk60mhsp1_ck
=
ERR_PTR
(
-
ENODEV
);
omap
->
xclk60mhsp2_ck
=
ERR_PTR
(
-
ENODEV
);
for
(
i
=
0
;
i
<
omap
->
nports
;
i
++
)
{
if
(
is_ehci_phy_mode
(
i
)
||
is_ehci_tll_mode
(
i
)
||
is_ehci_hsic_mode
(
i
))
need_logic_fck
|=
true
;
omap
->
utmi_clk
[
i
]
=
ERR_PTR
(
-
ENODEV
);
omap
->
hsic480m_clk
[
i
]
=
ERR_PTR
(
-
ENODEV
);
omap
->
hsic60m_clk
[
i
]
=
ERR_PTR
(
-
ENODEV
)
;
}
omap
->
ehci_logic_fck
=
ERR_PTR
(
-
EINVAL
);
if
(
need_logic_fck
)
{
omap
->
ehci_logic_fck
=
clk_get
(
dev
,
"ehci_logic_fck"
);
if
(
IS_ERR
(
omap
->
ehci_logic_fck
))
{
ret
=
PTR_ERR
(
omap
->
ehci_logic_fck
);
dev_dbg
(
dev
,
"ehci_logic_fck failed:%d
\n
"
,
ret
);
/* for OMAP3 i.e. USBHS REV1 */
if
(
omap
->
usbhs_rev
==
OMAP_USBHS_REV1
)
{
need_logic_fck
=
false
;
for
(
i
=
0
;
i
<
omap
->
nports
;
i
++
)
{
if
(
is_ehci_phy_mode
(
pdata
->
port_mode
[
i
])
||
is_ehci_tll_mode
(
pdata
->
port_mode
[
i
])
||
is_ehci_hsic_mode
(
pdata
->
port_mode
[
i
]))
need_logic_fck
|=
true
;
}
if
(
need_logic_fck
)
{
omap
->
ehci_logic_fck
=
devm_clk_get
(
dev
,
"usbhost_120m_fck"
);
if
(
IS_ERR
(
omap
->
ehci_logic_fck
))
{
ret
=
PTR_ERR
(
omap
->
ehci_logic_fck
);
dev_err
(
dev
,
"usbhost_120m_fck failed:%d
\n
"
,
ret
);
goto
err_mem
;
}
}
goto
initialize
;
}
omap
->
utmi_p1_gfclk
=
clk_get
(
dev
,
"utmi_p1_gfclk"
);
/* for OMAP4+ i.e. USBHS REV2+ */
omap
->
utmi_p1_gfclk
=
devm_clk_get
(
dev
,
"utmi_p1_gfclk"
);
if
(
IS_ERR
(
omap
->
utmi_p1_gfclk
))
{
ret
=
PTR_ERR
(
omap
->
utmi_p1_gfclk
);
dev_err
(
dev
,
"utmi_p1_gfclk failed error:%d
\n
"
,
ret
);
goto
err_
p1_gfclk
;
goto
err_
mem
;
}
omap
->
utmi_p2_gfclk
=
clk_get
(
dev
,
"utmi_p2_gfclk"
);
omap
->
utmi_p2_gfclk
=
devm_
clk_get
(
dev
,
"utmi_p2_gfclk"
);
if
(
IS_ERR
(
omap
->
utmi_p2_gfclk
))
{
ret
=
PTR_ERR
(
omap
->
utmi_p2_gfclk
);
dev_err
(
dev
,
"utmi_p2_gfclk failed error:%d
\n
"
,
ret
);
goto
err_
p2_gfclk
;
goto
err_
mem
;
}
omap
->
xclk60mhsp1_ck
=
clk_get
(
dev
,
"
x
clk60m
hsp1_ck
"
);
omap
->
xclk60mhsp1_ck
=
devm_
clk_get
(
dev
,
"
ref
clk
_
60m
_ext_p1
"
);
if
(
IS_ERR
(
omap
->
xclk60mhsp1_ck
))
{
ret
=
PTR_ERR
(
omap
->
xclk60mhsp1_ck
);
dev_err
(
dev
,
"
x
clk60m
hsp1_ck
failed error:%d
\n
"
,
ret
);
goto
err_
xclk60mhsp1
;
dev_err
(
dev
,
"
ref
clk
_
60m
_ext_p1
failed error:%d
\n
"
,
ret
);
goto
err_
mem
;
}
omap
->
xclk60mhsp2_ck
=
clk_get
(
dev
,
"
x
clk60m
hsp2_ck
"
);
omap
->
xclk60mhsp2_ck
=
devm_
clk_get
(
dev
,
"
ref
clk
_
60m
_ext_p2
"
);
if
(
IS_ERR
(
omap
->
xclk60mhsp2_ck
))
{
ret
=
PTR_ERR
(
omap
->
xclk60mhsp2_ck
);
dev_err
(
dev
,
"
x
clk60m
hsp2_ck
failed error:%d
\n
"
,
ret
);
goto
err_
xclk60mhsp2
;
dev_err
(
dev
,
"
ref
clk
_
60m
_ext_p2
failed error:%d
\n
"
,
ret
);
goto
err_
mem
;
}
omap
->
init_60m_fclk
=
clk_get
(
dev
,
"
init
_60m_
fclk
"
);
omap
->
init_60m_fclk
=
devm_
clk_get
(
dev
,
"
refclk
_60m_
int
"
);
if
(
IS_ERR
(
omap
->
init_60m_fclk
))
{
ret
=
PTR_ERR
(
omap
->
init_60m_fclk
);
dev_err
(
dev
,
"
init
_60m_
fclk
failed error:%d
\n
"
,
ret
);
goto
err_
init60
m
;
dev_err
(
dev
,
"
refclk
_60m_
int
failed error:%d
\n
"
,
ret
);
goto
err_
me
m
;
}
for
(
i
=
0
;
i
<
omap
->
nports
;
i
++
)
{
...
...
@@ -727,55 +750,72 @@ static int usbhs_omap_probe(struct platform_device *pdev)
* platforms have all clocks and we can function without
* them
*/
omap
->
utmi_clk
[
i
]
=
clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
utmi_clk
[
i
]))
dev_dbg
(
dev
,
"Failed to get clock : %s : %ld
\n
"
,
clkname
,
PTR_ERR
(
omap
->
utmi_clk
[
i
]));
omap
->
utmi_clk
[
i
]
=
devm_clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
utmi_clk
[
i
]))
{
ret
=
PTR_ERR
(
omap
->
utmi_clk
[
i
]);
dev_err
(
dev
,
"Failed to get clock : %s : %d
\n
"
,
clkname
,
ret
);
goto
err_mem
;
}
snprintf
(
clkname
,
sizeof
(
clkname
),
"usb_host_hs_hsic480m_p%d_clk"
,
i
+
1
);
omap
->
hsic480m_clk
[
i
]
=
clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
hsic480m_clk
[
i
]))
dev_dbg
(
dev
,
"Failed to get clock : %s : %ld
\n
"
,
clkname
,
PTR_ERR
(
omap
->
hsic480m_clk
[
i
]));
omap
->
hsic480m_clk
[
i
]
=
devm_clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
hsic480m_clk
[
i
]))
{
ret
=
PTR_ERR
(
omap
->
hsic480m_clk
[
i
]);
dev_err
(
dev
,
"Failed to get clock : %s : %d
\n
"
,
clkname
,
ret
);
goto
err_mem
;
}
snprintf
(
clkname
,
sizeof
(
clkname
),
"usb_host_hs_hsic60m_p%d_clk"
,
i
+
1
);
omap
->
hsic60m_clk
[
i
]
=
clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
hsic60m_clk
[
i
]))
dev_dbg
(
dev
,
"Failed to get clock : %s : %ld
\n
"
,
clkname
,
PTR_ERR
(
omap
->
hsic60m_clk
[
i
]));
omap
->
hsic60m_clk
[
i
]
=
devm_clk_get
(
dev
,
clkname
);
if
(
IS_ERR
(
omap
->
hsic60m_clk
[
i
]))
{
ret
=
PTR_ERR
(
omap
->
hsic60m_clk
[
i
]);
dev_err
(
dev
,
"Failed to get clock : %s : %d
\n
"
,
clkname
,
ret
);
goto
err_mem
;
}
}
if
(
is_ehci_phy_mode
(
pdata
->
port_mode
[
0
]))
{
/* for OMAP3, clk_set_parent fails */
ret
=
clk_set_parent
(
omap
->
utmi_p1_gfclk
,
omap
->
xclk60mhsp1_ck
);
if
(
ret
!=
0
)
dev_dbg
(
dev
,
"xclk60mhsp1_ck set parent failed: %d
\n
"
,
ret
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"xclk60mhsp1_ck set parent failed: %d
\n
"
,
ret
);
goto
err_mem
;
}
}
else
if
(
is_ehci_tll_mode
(
pdata
->
port_mode
[
0
]))
{
ret
=
clk_set_parent
(
omap
->
utmi_p1_gfclk
,
omap
->
init_60m_fclk
);
if
(
ret
!=
0
)
dev_dbg
(
dev
,
"P0 init_60m_fclk set parent failed: %d
\n
"
,
ret
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"P0 init_60m_fclk set parent failed: %d
\n
"
,
ret
);
goto
err_mem
;
}
}
if
(
is_ehci_phy_mode
(
pdata
->
port_mode
[
1
]))
{
ret
=
clk_set_parent
(
omap
->
utmi_p2_gfclk
,
omap
->
xclk60mhsp2_ck
);
if
(
ret
!=
0
)
dev_dbg
(
dev
,
"xclk60mhsp2_ck set parent failed: %d
\n
"
,
ret
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"xclk60mhsp2_ck set parent failed: %d
\n
"
,
ret
);
goto
err_mem
;
}
}
else
if
(
is_ehci_tll_mode
(
pdata
->
port_mode
[
1
]))
{
ret
=
clk_set_parent
(
omap
->
utmi_p2_gfclk
,
omap
->
init_60m_fclk
);
if
(
ret
!=
0
)
dev_dbg
(
dev
,
"P1 init_60m_fclk set parent failed: %d
\n
"
,
ret
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"P1 init_60m_fclk set parent failed: %d
\n
"
,
ret
);
goto
err_mem
;
}
}
initialize:
omap_usbhs_init
(
dev
);
if
(
dev
->
of_node
)
{
...
...
@@ -784,7 +824,7 @@ static int usbhs_omap_probe(struct platform_device *pdev)
if
(
ret
)
{
dev_err
(
dev
,
"Failed to create DT children: %d
\n
"
,
ret
);
goto
err_
alloc
;
goto
err_
mem
;
}
}
else
{
...
...
@@ -792,40 +832,12 @@ static int usbhs_omap_probe(struct platform_device *pdev)
if
(
ret
)
{
dev_err
(
dev
,
"omap_usbhs_alloc_children failed: %d
\n
"
,
ret
);
goto
err_
alloc
;
goto
err_
mem
;
}
}
return
0
;
err_alloc:
for
(
i
=
0
;
i
<
omap
->
nports
;
i
++
)
{
if
(
!
IS_ERR
(
omap
->
utmi_clk
[
i
]))
clk_put
(
omap
->
utmi_clk
[
i
]);
if
(
!
IS_ERR
(
omap
->
hsic60m_clk
[
i
]))
clk_put
(
omap
->
hsic60m_clk
[
i
]);
if
(
!
IS_ERR
(
omap
->
hsic480m_clk
[
i
]))
clk_put
(
omap
->
hsic480m_clk
[
i
]);
}
clk_put
(
omap
->
init_60m_fclk
);
err_init60m:
clk_put
(
omap
->
xclk60mhsp2_ck
);
err_xclk60mhsp2:
clk_put
(
omap
->
xclk60mhsp1_ck
);
err_xclk60mhsp1:
clk_put
(
omap
->
utmi_p2_gfclk
);
err_p2_gfclk:
clk_put
(
omap
->
utmi_p1_gfclk
);
err_p1_gfclk:
if
(
!
IS_ERR
(
omap
->
ehci_logic_fck
))
clk_put
(
omap
->
ehci_logic_fck
);
err_mem:
pm_runtime_disable
(
dev
);
...
...
@@ -847,27 +859,6 @@ static int usbhs_omap_remove_child(struct device *dev, void *data)
*/
static
int
usbhs_omap_remove
(
struct
platform_device
*
pdev
)
{
struct
usbhs_hcd_omap
*
omap
=
platform_get_drvdata
(
pdev
);
int
i
;
for
(
i
=
0
;
i
<
omap
->
nports
;
i
++
)
{
if
(
!
IS_ERR
(
omap
->
utmi_clk
[
i
]))
clk_put
(
omap
->
utmi_clk
[
i
]);
if
(
!
IS_ERR
(
omap
->
hsic60m_clk
[
i
]))
clk_put
(
omap
->
hsic60m_clk
[
i
]);
if
(
!
IS_ERR
(
omap
->
hsic480m_clk
[
i
]))
clk_put
(
omap
->
hsic480m_clk
[
i
]);
}
clk_put
(
omap
->
init_60m_fclk
);
clk_put
(
omap
->
utmi_p1_gfclk
);
clk_put
(
omap
->
utmi_p2_gfclk
);
clk_put
(
omap
->
xclk60mhsp2_ck
);
clk_put
(
omap
->
xclk60mhsp1_ck
);
if
(
!
IS_ERR
(
omap
->
ehci_logic_fck
))
clk_put
(
omap
->
ehci_logic_fck
);
pm_runtime_disable
(
&
pdev
->
dev
);
/* remove children */
...
...
This diff is collapsed.
Click to expand it.
drivers/mfd/omap-usb-tll.c
View file @
1a55361e
...
...
@@ -252,7 +252,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
break
;
}
tll
->
ch_clk
=
devm_kzalloc
(
dev
,
sizeof
(
struct
clk
*
[
tll
->
nch
])
,
tll
->
ch_clk
=
devm_kzalloc
(
dev
,
sizeof
(
struct
clk
*
)
*
tll
->
nch
,
GFP_KERNEL
);
if
(
!
tll
->
ch_clk
)
{
ret
=
-
ENOMEM
;
...
...
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