Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
9c602713
Commit
9c602713
authored
Nov 14, 2017
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/stm' into for-linus
parents
2c852859
d83f4131
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
2213 additions
and
1 deletion
+2213
-1
Documentation/devicetree/bindings/dma/stm32-dma.txt
Documentation/devicetree/bindings/dma/stm32-dma.txt
+3
-1
Documentation/devicetree/bindings/dma/stm32-dmamux.txt
Documentation/devicetree/bindings/dma/stm32-dmamux.txt
+84
-0
Documentation/devicetree/bindings/dma/stm32-mdma.txt
Documentation/devicetree/bindings/dma/stm32-mdma.txt
+94
-0
drivers/dma/Kconfig
drivers/dma/Kconfig
+21
-0
drivers/dma/Makefile
drivers/dma/Makefile
+2
-0
drivers/dma/stm32-dmamux.c
drivers/dma/stm32-dmamux.c
+327
-0
drivers/dma/stm32-mdma.c
drivers/dma/stm32-mdma.c
+1682
-0
No files found.
Documentation/devicetree/bindings/dma/stm32-dma.txt
View file @
9c602713
...
...
@@ -13,6 +13,7 @@ Required properties:
- #dma-cells : Must be <4>. See DMA client paragraph for more details.
Optional properties:
- dma-requests : Number of DMA requests supported.
- resets: Reference to a reset controller asserting the DMA controller
- st,mem2mem: boolean; if defined, it indicates that the controller supports
memory-to-memory transfer
...
...
@@ -34,12 +35,13 @@ Example:
#dma-cells = <4>;
st,mem2mem;
resets = <&rcc 150>;
dma-requests = <8>;
};
* DMA client
DMA clients connected to the STM32 DMA controller must use the format
described in the dma.txt file, using a f
ive
-cell specifier for each
described in the dma.txt file, using a f
our
-cell specifier for each
channel: a phandle to the DMA controller plus the following four integer cells:
1. The channel id
...
...
Documentation/devicetree/bindings/dma/stm32-dmamux.txt
0 → 100644
View file @
9c602713
STM32 DMA MUX (DMA request router)
Required properties:
- compatible: "st,stm32h7-dmamux"
- reg: Memory map for accessing module
- #dma-cells: Should be set to <3>.
First parameter is request line number.
Second is DMA channel configuration
Third is Fifo threshold
For more details about the three cells, please see
stm32-dma.txt documentation binding file
- dma-masters: Phandle pointing to the DMA controllers.
Several controllers are allowed. Only "st,stm32-dma" DMA
compatible are supported.
Optional properties:
- dma-channels : Number of DMA requests supported.
- dma-requests : Number of DMAMUX requests supported.
- resets: Reference to a reset controller asserting the DMA controller
- clocks: Input clock of the DMAMUX instance.
Example:
/* DMA controller 1 */
dma1: dma-controller@40020000 {
compatible = "st,stm32-dma";
reg = <0x40020000 0x400>;
interrupts = <11>,
<12>,
<13>,
<14>,
<15>,
<16>,
<17>,
<47>;
clocks = <&timer_clk>;
#dma-cells = <4>;
st,mem2mem;
resets = <&rcc 150>;
dma-channels = <8>;
dma-requests = <8>;
};
/* DMA controller 1 */
dma2: dma@40020400 {
compatible = "st,stm32-dma";
reg = <0x40020400 0x400>;
interrupts = <56>,
<57>,
<58>,
<59>,
<60>,
<68>,
<69>,
<70>;
clocks = <&timer_clk>;
#dma-cells = <4>;
st,mem2mem;
resets = <&rcc 150>;
dma-channels = <8>;
dma-requests = <8>;
};
/* DMA mux */
dmamux1: dma-router@40020800 {
compatible = "st,stm32h7-dmamux";
reg = <0x40020800 0x3c>;
#dma-cells = <3>;
dma-requests = <128>;
dma-channels = <16>;
dma-masters = <&dma1 &dma2>;
clocks = <&timer_clk>;
};
/* DMA client */
usart1: serial@40011000 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40011000 0x400>;
interrupts = <37>;
clocks = <&timer_clk>;
dmas = <&dmamux1 41 0x414 0>,
<&dmamux1 42 0x414 0>;
dma-names = "rx", "tx";
};
Documentation/devicetree/bindings/dma/stm32-mdma.txt
0 → 100644
View file @
9c602713
* STMicroelectronics STM32 MDMA controller
The STM32 MDMA is a general-purpose direct memory access controller capable of
supporting 64 independent DMA channels with 256 HW requests.
Required properties:
- compatible: Should be "st,stm32h7-mdma"
- reg: Should contain MDMA registers location and length. This should include
all of the per-channel registers.
- interrupts: Should contain the MDMA interrupt.
- clocks: Should contain the input clock of the DMA instance.
- resets: Reference to a reset controller asserting the DMA controller.
- #dma-cells : Must be <5>. See DMA client paragraph for more details.
Optional properties:
- dma-channels: Number of DMA channels supported by the controller.
- dma-requests: Number of DMA request signals supported by the controller.
- st,ahb-addr-masks: Array of u32 mask to list memory devices addressed via
AHB bus.
Example:
mdma1: dma@52000000 {
compatible = "st,stm32h7-mdma";
reg = <0x52000000 0x1000>;
interrupts = <122>;
clocks = <&timer_clk>;
resets = <&rcc 992>;
#dma-cells = <5>;
dma-channels = <16>;
dma-requests = <32>;
st,ahb-addr-masks = <0x20000000>, <0x00000000>;
};
* DMA client
DMA clients connected to the STM32 MDMA controller must use the format
described in the dma.txt file, using a five-cell specifier for each channel:
a phandle to the MDMA controller plus the following five integer cells:
1. The request line number
2. The priority level
0x00: Low
0x01: Medium
0x10: High
0x11: Very high
3. A 32bit mask specifying the DMA channel configuration
-bit 0-1: Source increment mode
0x00: Source address pointer is fixed
0x10: Source address pointer is incremented after each data transfer
0x11: Source address pointer is decremented after each data transfer
-bit 2-3: Destination increment mode
0x00: Destination address pointer is fixed
0x10: Destination address pointer is incremented after each data
transfer
0x11: Destination address pointer is decremented after each data
transfer
-bit 8-9: Source increment offset size
0x00: byte (8bit)
0x01: half-word (16bit)
0x10: word (32bit)
0x11: double-word (64bit)
-bit 10-11: Destination increment offset size
0x00: byte (8bit)
0x01: half-word (16bit)
0x10: word (32bit)
0x11: double-word (64bit)
-bit 25-18: The number of bytes to be transferred in a single transfer
(min = 1 byte, max = 128 bytes)
-bit 29:28: Trigger Mode
0x00: Each MDMA request triggers a buffer transfer (max 128 bytes)
0x01: Each MDMA request triggers a block transfer (max 64K bytes)
0x10: Each MDMA request triggers a repeated block transfer
0x11: Each MDMA request triggers a linked list transfer
4. A 32bit value specifying the register to be used to acknowledge the request
if no HW ack signal is used by the MDMA client
5. A 32bit mask specifying the value to be written to acknowledge the request
if no HW ack signal is used by the MDMA client
Example:
i2c4: i2c@5c002000 {
compatible = "st,stm32f7-i2c";
reg = <0x5c002000 0x400>;
interrupts = <95>,
<96>;
clocks = <&timer_clk>;
#address-cells = <1>;
#size-cells = <0>;
dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>,
<&mdma1 37 0x0 0x40002 0x0 0x0>;
dma-names = "rx", "tx";
status = "disabled";
};
drivers/dma/Kconfig
View file @
9c602713
...
...
@@ -483,6 +483,27 @@ config STM32_DMA
If you have a board based on such a MCU and wish to use DMA say Y
here.
config STM32_DMAMUX
bool "STMicroelectronics STM32 dma multiplexer support"
depends on STM32_DMA || COMPILE_TEST
help
Enable support for the on-chip DMA multiplexer on STMicroelectronics
STM32 MCUs.
If you have a board based on such a MCU and wish to use DMAMUX say Y
here.
config STM32_MDMA
bool "STMicroelectronics STM32 master dma support"
depends on ARCH_STM32 || COMPILE_TEST
depends on OF
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
Enable support for the on-chip MDMA controller on STMicroelectronics
STM32 platforms.
If you have a board based on STM32 SoC and wish to use the master DMA
say Y here.
config S3C24XX_DMAC
bool "Samsung S3C24XX DMA support"
depends on ARCH_S3C24XX || COMPILE_TEST
...
...
drivers/dma/Makefile
View file @
9c602713
...
...
@@ -59,6 +59,8 @@ obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_SIRF_DMA)
+=
sirf-dma.o
obj-$(CONFIG_STE_DMA40)
+=
ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_STM32_DMA)
+=
stm32-dma.o
obj-$(CONFIG_STM32_DMAMUX)
+=
stm32-dmamux.o
obj-$(CONFIG_STM32_MDMA)
+=
stm32-mdma.o
obj-$(CONFIG_S3C24XX_DMAC)
+=
s3c24xx-dma.o
obj-$(CONFIG_TXX9_DMAC)
+=
txx9dmac.o
obj-$(CONFIG_TEGRA20_APB_DMA)
+=
tegra20-apb-dma.o
...
...
drivers/dma/stm32-dmamux.c
0 → 100644
View file @
9c602713
/*
*
* Copyright (C) STMicroelectronics SA 2017
* Author(s): M'boumba Cedric Madianga <cedric.madianga@gmail.com>
* Pierre-Yves Mordret <pierre-yves.mordret@st.com>
*
* License terms: GPL V2.0.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* DMA Router driver for STM32 DMA MUX
*
* Based on TI DMA Crossbar driver
*
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#define STM32_DMAMUX_CCR(x) (0x4 * (x))
#define STM32_DMAMUX_MAX_DMA_REQUESTS 32
#define STM32_DMAMUX_MAX_REQUESTS 255
struct
stm32_dmamux
{
u32
master
;
u32
request
;
u32
chan_id
;
};
struct
stm32_dmamux_data
{
struct
dma_router
dmarouter
;
struct
clk
*
clk
;
struct
reset_control
*
rst
;
void
__iomem
*
iomem
;
u32
dma_requests
;
/* Number of DMA requests connected to DMAMUX */
u32
dmamux_requests
;
/* Number of DMA requests routed toward DMAs */
spinlock_t
lock
;
/* Protects register access */
unsigned
long
*
dma_inuse
;
/* Used DMA channel */
u32
dma_reqs
[];
/* Number of DMA Request per DMA masters.
* [0] holds number of DMA Masters.
* To be kept at very end end of this structure
*/
};
static
inline
u32
stm32_dmamux_read
(
void
__iomem
*
iomem
,
u32
reg
)
{
return
readl_relaxed
(
iomem
+
reg
);
}
static
inline
void
stm32_dmamux_write
(
void
__iomem
*
iomem
,
u32
reg
,
u32
val
)
{
writel_relaxed
(
val
,
iomem
+
reg
);
}
static
void
stm32_dmamux_free
(
struct
device
*
dev
,
void
*
route_data
)
{
struct
stm32_dmamux_data
*
dmamux
=
dev_get_drvdata
(
dev
);
struct
stm32_dmamux
*
mux
=
route_data
;
unsigned
long
flags
;
/* Clear dma request */
spin_lock_irqsave
(
&
dmamux
->
lock
,
flags
);
stm32_dmamux_write
(
dmamux
->
iomem
,
STM32_DMAMUX_CCR
(
mux
->
chan_id
),
0
);
clear_bit
(
mux
->
chan_id
,
dmamux
->
dma_inuse
);
if
(
!
IS_ERR
(
dmamux
->
clk
))
clk_disable
(
dmamux
->
clk
);
spin_unlock_irqrestore
(
&
dmamux
->
lock
,
flags
);
dev_dbg
(
dev
,
"Unmapping DMAMUX(%u) to DMA%u(%u)
\n
"
,
mux
->
request
,
mux
->
master
,
mux
->
chan_id
);
kfree
(
mux
);
}
static
void
*
stm32_dmamux_route_allocate
(
struct
of_phandle_args
*
dma_spec
,
struct
of_dma
*
ofdma
)
{
struct
platform_device
*
pdev
=
of_find_device_by_node
(
ofdma
->
of_node
);
struct
stm32_dmamux_data
*
dmamux
=
platform_get_drvdata
(
pdev
);
struct
stm32_dmamux
*
mux
;
u32
i
,
min
,
max
;
int
ret
;
unsigned
long
flags
;
if
(
dma_spec
->
args_count
!=
3
)
{
dev_err
(
&
pdev
->
dev
,
"invalid number of dma mux args
\n
"
);
return
ERR_PTR
(
-
EINVAL
);
}
if
(
dma_spec
->
args
[
0
]
>
dmamux
->
dmamux_requests
)
{
dev_err
(
&
pdev
->
dev
,
"invalid mux request number: %d
\n
"
,
dma_spec
->
args
[
0
]);
return
ERR_PTR
(
-
EINVAL
);
}
mux
=
kzalloc
(
sizeof
(
*
mux
),
GFP_KERNEL
);
if
(
!
mux
)
return
ERR_PTR
(
-
ENOMEM
);
spin_lock_irqsave
(
&
dmamux
->
lock
,
flags
);
mux
->
chan_id
=
find_first_zero_bit
(
dmamux
->
dma_inuse
,
dmamux
->
dma_requests
);
set_bit
(
mux
->
chan_id
,
dmamux
->
dma_inuse
);
spin_unlock_irqrestore
(
&
dmamux
->
lock
,
flags
);
if
(
mux
->
chan_id
==
dmamux
->
dma_requests
)
{
dev_err
(
&
pdev
->
dev
,
"Run out of free DMA requests
\n
"
);
ret
=
-
ENOMEM
;
goto
error
;
}
/* Look for DMA Master */
for
(
i
=
1
,
min
=
0
,
max
=
dmamux
->
dma_reqs
[
i
];
i
<=
dmamux
->
dma_reqs
[
0
];
min
+=
dmamux
->
dma_reqs
[
i
],
max
+=
dmamux
->
dma_reqs
[
++
i
])
if
(
mux
->
chan_id
<
max
)
break
;
mux
->
master
=
i
-
1
;
/* The of_node_put() will be done in of_dma_router_xlate function */
dma_spec
->
np
=
of_parse_phandle
(
ofdma
->
of_node
,
"dma-masters"
,
i
-
1
);
if
(
!
dma_spec
->
np
)
{
dev_err
(
&
pdev
->
dev
,
"can't get dma master
\n
"
);
ret
=
-
EINVAL
;
goto
error
;
}
/* Set dma request */
spin_lock_irqsave
(
&
dmamux
->
lock
,
flags
);
if
(
!
IS_ERR
(
dmamux
->
clk
))
{
ret
=
clk_enable
(
dmamux
->
clk
);
if
(
ret
<
0
)
{
spin_unlock_irqrestore
(
&
dmamux
->
lock
,
flags
);
dev_err
(
&
pdev
->
dev
,
"clk_prep_enable issue: %d
\n
"
,
ret
);
goto
error
;
}
}
spin_unlock_irqrestore
(
&
dmamux
->
lock
,
flags
);
mux
->
request
=
dma_spec
->
args
[
0
];
/* craft DMA spec */
dma_spec
->
args
[
3
]
=
dma_spec
->
args
[
2
];
dma_spec
->
args
[
2
]
=
dma_spec
->
args
[
1
];
dma_spec
->
args
[
1
]
=
0
;
dma_spec
->
args
[
0
]
=
mux
->
chan_id
-
min
;
dma_spec
->
args_count
=
4
;
stm32_dmamux_write
(
dmamux
->
iomem
,
STM32_DMAMUX_CCR
(
mux
->
chan_id
),
mux
->
request
);
dev_dbg
(
&
pdev
->
dev
,
"Mapping DMAMUX(%u) to DMA%u(%u)
\n
"
,
mux
->
request
,
mux
->
master
,
mux
->
chan_id
);
return
mux
;
error:
clear_bit
(
mux
->
chan_id
,
dmamux
->
dma_inuse
);
kfree
(
mux
);
return
ERR_PTR
(
ret
);
}
static
const
struct
of_device_id
stm32_stm32dma_master_match
[]
=
{
{
.
compatible
=
"st,stm32-dma"
,
},
{},
};
static
int
stm32_dmamux_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
const
struct
of_device_id
*
match
;
struct
device_node
*
dma_node
;
struct
stm32_dmamux_data
*
stm32_dmamux
;
struct
resource
*
res
;
void
__iomem
*
iomem
;
int
i
,
count
,
ret
;
u32
dma_req
;
if
(
!
node
)
return
-
ENODEV
;
count
=
device_property_read_u32_array
(
&
pdev
->
dev
,
"dma-masters"
,
NULL
,
0
);
if
(
count
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Can't get DMA master(s) node
\n
"
);
return
-
ENODEV
;
}
stm32_dmamux
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
stm32_dmamux
)
+
sizeof
(
u32
)
*
(
count
+
1
),
GFP_KERNEL
);
if
(
!
stm32_dmamux
)
return
-
ENOMEM
;
dma_req
=
0
;
for
(
i
=
1
;
i
<=
count
;
i
++
)
{
dma_node
=
of_parse_phandle
(
node
,
"dma-masters"
,
i
-
1
);
match
=
of_match_node
(
stm32_stm32dma_master_match
,
dma_node
);
if
(
!
match
)
{
dev_err
(
&
pdev
->
dev
,
"DMA master is not supported
\n
"
);
of_node_put
(
dma_node
);
return
-
EINVAL
;
}
if
(
of_property_read_u32
(
dma_node
,
"dma-requests"
,
&
stm32_dmamux
->
dma_reqs
[
i
]))
{
dev_info
(
&
pdev
->
dev
,
"Missing MUX output information, using %u.
\n
"
,
STM32_DMAMUX_MAX_DMA_REQUESTS
);
stm32_dmamux
->
dma_reqs
[
i
]
=
STM32_DMAMUX_MAX_DMA_REQUESTS
;
}
dma_req
+=
stm32_dmamux
->
dma_reqs
[
i
];
of_node_put
(
dma_node
);
}
if
(
dma_req
>
STM32_DMAMUX_MAX_DMA_REQUESTS
)
{
dev_err
(
&
pdev
->
dev
,
"Too many DMA Master Requests to manage
\n
"
);
return
-
ENODEV
;
}
stm32_dmamux
->
dma_requests
=
dma_req
;
stm32_dmamux
->
dma_reqs
[
0
]
=
count
;
stm32_dmamux
->
dma_inuse
=
devm_kcalloc
(
&
pdev
->
dev
,
BITS_TO_LONGS
(
dma_req
),
sizeof
(
unsigned
long
),
GFP_KERNEL
);
if
(
!
stm32_dmamux
->
dma_inuse
)
return
-
ENOMEM
;
if
(
device_property_read_u32
(
&
pdev
->
dev
,
"dma-requests"
,
&
stm32_dmamux
->
dmamux_requests
))
{
stm32_dmamux
->
dmamux_requests
=
STM32_DMAMUX_MAX_REQUESTS
;
dev_warn
(
&
pdev
->
dev
,
"DMAMUX defaulting on %u requests
\n
"
,
stm32_dmamux
->
dmamux_requests
);
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
return
-
ENODEV
;
iomem
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
iomem
))
return
PTR_ERR
(
iomem
);
spin_lock_init
(
&
stm32_dmamux
->
lock
);
stm32_dmamux
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
stm32_dmamux
->
clk
))
{
ret
=
PTR_ERR
(
stm32_dmamux
->
clk
);
if
(
ret
==
-
EPROBE_DEFER
)
dev_info
(
&
pdev
->
dev
,
"Missing controller clock
\n
"
);
return
ret
;
}
stm32_dmamux
->
rst
=
devm_reset_control_get
(
&
pdev
->
dev
,
NULL
);
if
(
!
IS_ERR
(
stm32_dmamux
->
rst
))
{
reset_control_assert
(
stm32_dmamux
->
rst
);
udelay
(
2
);
reset_control_deassert
(
stm32_dmamux
->
rst
);
}
stm32_dmamux
->
iomem
=
iomem
;
stm32_dmamux
->
dmarouter
.
dev
=
&
pdev
->
dev
;
stm32_dmamux
->
dmarouter
.
route_free
=
stm32_dmamux_free
;
platform_set_drvdata
(
pdev
,
stm32_dmamux
);
if
(
!
IS_ERR
(
stm32_dmamux
->
clk
))
{
ret
=
clk_prepare_enable
(
stm32_dmamux
->
clk
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"clk_prep_enable error: %d
\n
"
,
ret
);
return
ret
;
}
}
/* Reset the dmamux */
for
(
i
=
0
;
i
<
stm32_dmamux
->
dma_requests
;
i
++
)
stm32_dmamux_write
(
stm32_dmamux
->
iomem
,
STM32_DMAMUX_CCR
(
i
),
0
);
if
(
!
IS_ERR
(
stm32_dmamux
->
clk
))
clk_disable
(
stm32_dmamux
->
clk
);
return
of_dma_router_register
(
node
,
stm32_dmamux_route_allocate
,
&
stm32_dmamux
->
dmarouter
);
}
static
const
struct
of_device_id
stm32_dmamux_match
[]
=
{
{
.
compatible
=
"st,stm32h7-dmamux"
},
{},
};
static
struct
platform_driver
stm32_dmamux_driver
=
{
.
probe
=
stm32_dmamux_probe
,
.
driver
=
{
.
name
=
"stm32-dmamux"
,
.
of_match_table
=
stm32_dmamux_match
,
},
};
static
int
__init
stm32_dmamux_init
(
void
)
{
return
platform_driver_register
(
&
stm32_dmamux_driver
);
}
arch_initcall
(
stm32_dmamux_init
);
MODULE_DESCRIPTION
(
"DMA Router driver for STM32 DMA MUX"
);
MODULE_AUTHOR
(
"M'boumba Cedric Madianga <cedric.madianga@gmail.com>"
);
MODULE_AUTHOR
(
"Pierre-Yves Mordret <pierre-yves.mordret@st.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/dma/stm32-mdma.c
0 → 100644
View file @
9c602713
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