Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
0a2cdd88
Commit
0a2cdd88
authored
Oct 11, 2007
by
Josh Boyer
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'virtex-for-2.6.24' of
git://git.secretlab.ca/git/linux-2.6-virtex
into for-2.6.24-4xx
parents
cdec12ae
17c5c209
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
203 additions
and
84 deletions
+203
-84
MAINTAINERS
MAINTAINERS
+1
-1
arch/powerpc/boot/uartlite.c
arch/powerpc/boot/uartlite.c
+2
-2
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/Makefile
+1
-1
drivers/video/xilinxfb.c
drivers/video/xilinxfb.c
+199
-80
No files found.
MAINTAINERS
View file @
0a2cdd88
...
@@ -2306,7 +2306,7 @@ S: Maintained
...
@@ -2306,7 +2306,7 @@ S: Maintained
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
P: Grant Likely
P: Grant Likely
M: grant.likely@secretlab.ca
M: grant.likely@secretlab.ca
W: http://w
ww.secretlab.ca/
W: http://w
iki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex
L: linuxppc-dev@ozlabs.org
L: linuxppc-dev@ozlabs.org
S: Maintained
S: Maintained
...
...
arch/powerpc/boot/uartlite.c
View file @
0a2cdd88
...
@@ -45,8 +45,8 @@ static void uartlite_putc(unsigned char c)
...
@@ -45,8 +45,8 @@ static void uartlite_putc(unsigned char c)
static
unsigned
char
uartlite_getc
(
void
)
static
unsigned
char
uartlite_getc
(
void
)
{
{
u32
reg
=
ULITE_STATUS_RXVALID
;
u32
reg
=
0
;
while
(
reg
&
ULITE_STATUS_RXVALID
)
/* spin on
RXVALID bit */
while
(
!
(
reg
&
ULITE_STATUS_RXVALID
))
/* spin waiting for
RXVALID bit */
reg
=
in_be32
(
reg_base
+
ULITE_STATUS
);
reg
=
in_be32
(
reg_base
+
ULITE_STATUS
);
return
in_be32
(
reg_base
+
ULITE_RX
);
return
in_be32
(
reg_base
+
ULITE_RX
);
}
}
...
...
arch/powerpc/sysdev/Makefile
View file @
0a2cdd88
...
@@ -6,7 +6,6 @@ mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
...
@@ -6,7 +6,6 @@ mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
obj-$(CONFIG_MPIC)
+=
mpic.o
$
(
mpic-msi-obj-y
)
obj-$(CONFIG_MPIC)
+=
mpic.o
$
(
mpic-msi-obj-y
)
obj-$(CONFIG_PPC_MPC106)
+=
grackle.o
obj-$(CONFIG_PPC_MPC106)
+=
grackle.o
obj-$(CONFIG_PPC_DCR)
+=
dcr.o
obj-$(CONFIG_PPC_DCR_NATIVE)
+=
dcr-low.o
obj-$(CONFIG_PPC_DCR_NATIVE)
+=
dcr-low.o
obj-$(CONFIG_PPC_PMI)
+=
pmi.o
obj-$(CONFIG_PPC_PMI)
+=
pmi.o
obj-$(CONFIG_U3_DART)
+=
dart_iommu.o
obj-$(CONFIG_U3_DART)
+=
dart_iommu.o
...
@@ -33,6 +32,7 @@ endif
...
@@ -33,6 +32,7 @@ endif
ifeq
($(ARCH),powerpc)
ifeq
($(ARCH),powerpc)
obj-$(CONFIG_CPM)
+=
cpm_common.o
obj-$(CONFIG_CPM)
+=
cpm_common.o
obj-$(CONFIG_CPM2)
+=
cpm2_common.o cpm2_pic.o
obj-$(CONFIG_CPM2)
+=
cpm2_common.o cpm2_pic.o
obj-$(CONFIG_PPC_DCR)
+=
dcr.o
obj-$(CONFIG_8xx)
+=
mpc8xx_pic.o commproc.o
obj-$(CONFIG_8xx)
+=
mpc8xx_pic.o commproc.o
obj-$(CONFIG_UCODE_PATCH)
+=
micropatch.o
obj-$(CONFIG_UCODE_PATCH)
+=
micropatch.o
endif
endif
drivers/video/xilinxfb.c
View file @
0a2cdd88
...
@@ -6,9 +6,12 @@
...
@@ -6,9 +6,12 @@
* Author: MontaVista Software, Inc.
* Author: MontaVista Software, Inc.
* source@mvista.com
* source@mvista.com
*
*
* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
* 2002-2007 (c) MontaVista Software, Inc.
* terms of the GNU General Public License version 2. This program is licensed
* 2007 (c) Secret Lab Technologies, Ltd.
* "as is" without any warranty of any kind, whether express or implied.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
*/
/*
/*
...
@@ -18,6 +21,7 @@
...
@@ -18,6 +21,7 @@
* Geert Uytterhoeven.
* Geert Uytterhoeven.
*/
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/version.h>
...
@@ -28,7 +32,10 @@
...
@@ -28,7 +32,10 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#if defined(CONFIG_OF)
#include <linux/of_device.h>
#include <linux/of_platform.h>
#endif
#include <asm/io.h>
#include <asm/io.h>
#include <linux/xilinxfb.h>
#include <linux/xilinxfb.h>
...
@@ -111,7 +118,7 @@ struct xilinxfb_drvdata {
...
@@ -111,7 +118,7 @@ struct xilinxfb_drvdata {
u32
regs_phys
;
/* phys. address of the control registers */
u32
regs_phys
;
/* phys. address of the control registers */
u32
__iomem
*
regs
;
/* virt. address of the control registers */
u32
__iomem
*
regs
;
/* virt. address of the control registers */
unsigned
char
__iomem
*
fb_virt
;
/* virt. address of the frame buffer */
void
*
fb_virt
;
/* virt. address of the frame buffer */
dma_addr_t
fb_phys
;
/* phys. address of the frame buffer */
dma_addr_t
fb_phys
;
/* phys. address of the frame buffer */
u32
reg_ctrl_default
;
u32
reg_ctrl_default
;
...
@@ -195,130 +202,120 @@ static struct fb_ops xilinxfb_ops =
...
@@ -195,130 +202,120 @@ static struct fb_ops xilinxfb_ops =
.
fb_imageblit
=
cfb_imageblit
,
.
fb_imageblit
=
cfb_imageblit
,
};
};
/* === The device driver === */
/* ---------------------------------------------------------------------
* Bus independent setup/teardown
*/
static
int
static
int
xilinxfb_assign
(
struct
device
*
dev
,
unsigned
long
physaddr
,
xilinxfb_drv_probe
(
struct
device
*
dev
)
int
width_mm
,
int
height_mm
,
int
rotate
)
{
{
struct
platform_device
*
pdev
;
struct
xilinxfb_platform_data
*
pdata
;
struct
xilinxfb_drvdata
*
drvdata
;
struct
xilinxfb_drvdata
*
drvdata
;
struct
resource
*
regs_res
;
int
rc
;
int
retval
;
if
(
!
dev
)
return
-
EINVAL
;
pdev
=
to_platform_device
(
dev
);
pdata
=
pdev
->
dev
.
platform_data
;
/* Allocate the driver data region */
drvdata
=
kzalloc
(
sizeof
(
*
drvdata
),
GFP_KERNEL
);
drvdata
=
kzalloc
(
sizeof
(
*
drvdata
),
GFP_KERNEL
);
if
(
!
drvdata
)
{
if
(
!
drvdata
)
{
printk
(
KERN_ERR
"Couldn't allocate device private record
\n
"
);
dev_err
(
dev
,
"Couldn't allocate device private record
\n
"
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
dev_set_drvdata
(
dev
,
drvdata
);
dev_set_drvdata
(
dev
,
drvdata
);
/* Map the control registers in */
/* Map the control registers in */
regs_res
=
platform_get_resource
(
pdev
,
IORESOURCE_IO
,
0
);
if
(
!
request_mem_region
(
physaddr
,
8
,
DRIVER_NAME
))
{
if
(
!
regs_res
||
(
regs_res
->
end
-
regs_res
->
start
+
1
<
8
))
{
dev_err
(
dev
,
"Couldn't lock memory region at 0x%08lX
\n
"
,
printk
(
KERN_ERR
"Couldn't get registers resource
\n
"
);
physaddr
);
r
etval
=
-
EFAULT
;
r
c
=
-
ENODEV
;
goto
failed1
;
goto
err_region
;
}
}
drvdata
->
regs_phys
=
physaddr
;
if
(
!
request_mem_region
(
regs_res
->
start
,
8
,
DRIVER_NAME
))
{
drvdata
->
regs
=
ioremap
(
physaddr
,
8
);
printk
(
KERN_ERR
if
(
!
drvdata
->
regs
)
{
"Couldn't lock memory region at 0x%08
X
\n
"
,
dev_err
(
dev
,
"Couldn't lock memory region at 0x%08l
X
\n
"
,
regs_res
->
start
);
physaddr
);
r
etval
=
-
EBUSY
;
r
c
=
-
ENODEV
;
goto
failed1
;
goto
err_map
;
}
}
drvdata
->
regs
=
(
u32
__iomem
*
)
ioremap
(
regs_res
->
start
,
8
);
drvdata
->
regs_phys
=
regs_res
->
start
;
/* Allocate the framebuffer memory */
/* Allocate the framebuffer memory */
drvdata
->
fb_virt
=
dma_alloc_coherent
(
dev
,
PAGE_ALIGN
(
FB_SIZE
),
drvdata
->
fb_virt
=
dma_alloc_coherent
(
dev
,
PAGE_ALIGN
(
FB_SIZE
),
&
drvdata
->
fb_phys
,
GFP_KERNEL
);
&
drvdata
->
fb_phys
,
GFP_KERNEL
);
if
(
!
drvdata
->
fb_virt
)
{
if
(
!
drvdata
->
fb_virt
)
{
printk
(
KERN_ERR
"Could not allocate frame buffer memory
\n
"
);
dev_err
(
dev
,
"Could not allocate frame buffer memory
\n
"
);
r
etval
=
-
ENOMEM
;
r
c
=
-
ENOMEM
;
goto
failed2
;
goto
err_fbmem
;
}
}
/* Clear (turn to black) the framebuffer */
/* Clear (turn to black) the framebuffer */
memset_io
((
void
*
)
drvdata
->
fb_virt
,
0
,
FB_SIZE
);
memset_io
((
void
__iomem
*
)
drvdata
->
fb_virt
,
0
,
FB_SIZE
);
/* Tell the hardware where the frame buffer is */
/* Tell the hardware where the frame buffer is */
xilinx_fb_out_be32
(
drvdata
,
REG_FB_ADDR
,
drvdata
->
fb_phys
);
xilinx_fb_out_be32
(
drvdata
,
REG_FB_ADDR
,
drvdata
->
fb_phys
);
/* Turn on the display */
/* Turn on the display */
drvdata
->
reg_ctrl_default
=
REG_CTRL_ENABLE
;
drvdata
->
reg_ctrl_default
=
REG_CTRL_ENABLE
;
if
(
pdata
&&
pdata
->
rotate_screen
)
if
(
rotate
)
drvdata
->
reg_ctrl_default
|=
REG_CTRL_ROTATE
;
drvdata
->
reg_ctrl_default
|=
REG_CTRL_ROTATE
;
xilinx_fb_out_be32
(
drvdata
,
REG_CTRL
,
drvdata
->
reg_ctrl_default
);
xilinx_fb_out_be32
(
drvdata
,
REG_CTRL
,
drvdata
->
reg_ctrl_default
);
/* Fill struct fb_info */
/* Fill struct fb_info */
drvdata
->
info
.
device
=
dev
;
drvdata
->
info
.
device
=
dev
;
drvdata
->
info
.
screen_base
=
drvdata
->
fb_virt
;
drvdata
->
info
.
screen_base
=
(
void
__iomem
*
)
drvdata
->
fb_virt
;
drvdata
->
info
.
fbops
=
&
xilinxfb_ops
;
drvdata
->
info
.
fbops
=
&
xilinxfb_ops
;
drvdata
->
info
.
fix
=
xilinx_fb_fix
;
drvdata
->
info
.
fix
=
xilinx_fb_fix
;
drvdata
->
info
.
fix
.
smem_start
=
drvdata
->
fb_phys
;
drvdata
->
info
.
fix
.
smem_start
=
drvdata
->
fb_phys
;
drvdata
->
info
.
pseudo_palette
=
drvdata
->
pseudo_palette
;
drvdata
->
info
.
pseudo_palette
=
drvdata
->
pseudo_palette
;
drvdata
->
info
.
flags
=
FBINFO_DEFAULT
;
drvdata
->
info
.
var
=
xilinx_fb_var
;
xilinx_fb_var
.
height
=
height_mm
;
xilinx_fb_var
.
width
=
width_mm
;
if
(
fb_alloc_cmap
(
&
drvdata
->
info
.
cmap
,
PALETTE_ENTRIES_NO
,
0
)
<
0
)
{
/* Allocate a colour map */
printk
(
KERN_ERR
"Fail to allocate colormap (%d entries)
\n
"
,
rc
=
fb_alloc_cmap
(
&
drvdata
->
info
.
cmap
,
PALETTE_ENTRIES_NO
,
0
);
if
(
rc
)
{
dev_err
(
dev
,
"Fail to allocate colormap (%d entries)
\n
"
,
PALETTE_ENTRIES_NO
);
PALETTE_ENTRIES_NO
);
retval
=
-
EFAULT
;
goto
err_cmap
;
goto
failed3
;
}
}
drvdata
->
info
.
flags
=
FBINFO_DEFAULT
;
if
(
pdata
)
{
xilinx_fb_var
.
height
=
pdata
->
screen_height_mm
;
xilinx_fb_var
.
width
=
pdata
->
screen_width_mm
;
}
drvdata
->
info
.
var
=
xilinx_fb_var
;
/* Register new frame buffer */
/* Register new frame buffer */
if
(
register_framebuffer
(
&
drvdata
->
info
)
<
0
)
{
rc
=
register_framebuffer
(
&
drvdata
->
info
);
printk
(
KERN_ERR
"Could not register frame buffer
\n
"
);
if
(
rc
)
{
retval
=
-
EINVAL
;
dev_err
(
dev
,
"Could not register frame buffer
\n
"
)
;
goto
failed4
;
goto
err_regfb
;
}
}
/* Put a banner in the log (for DEBUG) */
dev_dbg
(
dev
,
"regs: phys=%lx, virt=%p
\n
"
,
physaddr
,
drvdata
->
regs
);
dev_dbg
(
dev
,
"fb: phys=%p, virt=%p, size=%x
\n
"
,
(
void
*
)
drvdata
->
fb_phys
,
drvdata
->
fb_virt
,
FB_SIZE
);
return
0
;
/* success */
return
0
;
/* success */
failed4
:
err_regfb
:
fb_dealloc_cmap
(
&
drvdata
->
info
.
cmap
);
fb_dealloc_cmap
(
&
drvdata
->
info
.
cmap
);
failed3
:
err_cmap
:
dma_free_coherent
(
dev
,
PAGE_ALIGN
(
FB_SIZE
),
drvdata
->
fb_virt
,
dma_free_coherent
(
dev
,
PAGE_ALIGN
(
FB_SIZE
),
drvdata
->
fb_virt
,
drvdata
->
fb_phys
);
drvdata
->
fb_phys
);
/* Turn off the display */
/* Turn off the display */
xilinx_fb_out_be32
(
drvdata
,
REG_CTRL
,
0
);
xilinx_fb_out_be32
(
drvdata
,
REG_CTRL
,
0
);
err_fbmem:
iounmap
(
drvdata
->
regs
);
iounmap
(
drvdata
->
regs
);
failed2
:
err_map
:
release_mem_region
(
regs_res
->
start
,
8
);
release_mem_region
(
physaddr
,
8
);
failed1
:
err_region
:
kfree
(
drvdata
);
kfree
(
drvdata
);
dev_set_drvdata
(
dev
,
NULL
);
dev_set_drvdata
(
dev
,
NULL
);
return
r
etval
;
return
r
c
;
}
}
static
int
static
int
xilinxfb_release
(
struct
device
*
dev
)
xilinxfb_drv_remove
(
struct
device
*
dev
)
{
{
struct
xilinxfb_drvdata
*
drvdata
;
struct
xilinxfb_drvdata
*
drvdata
=
dev_get_drvdata
(
dev
);
if
(
!
dev
)
return
-
ENODEV
;
drvdata
=
(
struct
xilinxfb_drvdata
*
)
dev_get_drvdata
(
dev
);
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
xilinx_fb_blank
(
VESA_POWERDOWN
,
&
drvdata
->
info
);
xilinx_fb_blank
(
VESA_POWERDOWN
,
&
drvdata
->
info
);
...
@@ -343,29 +340,151 @@ xilinxfb_drv_remove(struct device *dev)
...
@@ -343,29 +340,151 @@ xilinxfb_drv_remove(struct device *dev)
return
0
;
return
0
;
}
}
/* ---------------------------------------------------------------------
* Platform bus binding
*/
static
int
xilinxfb_platform_probe
(
struct
platform_device
*
pdev
)
{
struct
xilinxfb_platform_data
*
pdata
;
struct
resource
*
res
;
int
width_mm
=
0
;
int
height_mm
=
0
;
int
rotate
=
0
;
/* Find the registers address */
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IO
,
0
);
if
(
!
res
)
{
dev_err
(
&
pdev
->
dev
,
"Couldn't get registers resource
\n
"
);
return
-
ENODEV
;
}
/* If a pdata structure is provided, then extract the parameters */
pdata
=
pdev
->
dev
.
platform_data
;
if
(
pdata
)
{
height_mm
=
pdata
->
screen_height_mm
;
width_mm
=
pdata
->
screen_width_mm
;
rotate
=
pdata
->
rotate_screen
?
1
:
0
;
}
return
xilinxfb_assign
(
&
pdev
->
dev
,
res
->
start
,
width_mm
,
height_mm
,
rotate
);
}
static
int
xilinxfb_platform_remove
(
struct
platform_device
*
pdev
)
{
return
xilinxfb_release
(
&
pdev
->
dev
);
}
static
struct
device_driver
xilinxfb_driver
=
{
.
name
=
DRIVER_NAME
,
.
bus
=
&
platform_bus_type
,
.
probe
=
xilinxfb_drv_probe
,
static
struct
platform_driver
xilinxfb_platform_driver
=
{
.
remove
=
xilinxfb_drv_remove
.
probe
=
xilinxfb_platform_probe
,
.
remove
=
xilinxfb_platform_remove
,
.
driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
DRIVER_NAME
,
},
};
};
/* ---------------------------------------------------------------------
* OF bus binding
*/
#if defined(CONFIG_OF)
static
int
__devinit
xilinxfb_of_probe
(
struct
of_device
*
op
,
const
struct
of_device_id
*
match
)
{
struct
resource
res
;
const
u32
*
prop
;
int
width
=
0
,
height
=
0
,
rotate
=
0
;
int
size
,
rc
;
dev_dbg
(
&
op
->
dev
,
"xilinxfb_of_probe(%p, %p)
\n
"
,
op
,
match
);
rc
=
of_address_to_resource
(
op
->
node
,
0
,
&
res
);
if
(
rc
)
{
dev_err
(
&
op
->
dev
,
"invalid address
\n
"
);
return
rc
;
}
prop
=
of_get_property
(
op
->
node
,
"display-number"
,
&
size
);
if
((
prop
)
&&
(
size
>=
sizeof
(
u32
)
*
2
))
{
width
=
prop
[
0
];
height
=
prop
[
1
];
}
if
(
of_find_property
(
op
->
node
,
"rotate-display"
,
NULL
))
rotate
=
1
;
return
xilinxfb_assign
(
&
op
->
dev
,
res
.
start
,
width
,
height
,
rotate
);
}
static
int
__devexit
xilinxfb_of_remove
(
struct
of_device
*
op
)
{
return
xilinxfb_release
(
&
op
->
dev
);
}
/* Match table for of_platform binding */
static
struct
of_device_id
__devinit
xilinxfb_of_match
[]
=
{
{
.
compatible
=
"xilinx,ml300-fb"
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
xilinxfb_of_match
);
static
struct
of_platform_driver
xilinxfb_of_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
DRIVER_NAME
,
.
match_table
=
xilinxfb_of_match
,
.
probe
=
xilinxfb_of_probe
,
.
remove
=
__devexit_p
(
xilinxfb_of_remove
),
.
driver
=
{
.
name
=
DRIVER_NAME
,
},
};
/* Registration helpers to keep the number of #ifdefs to a minimum */
static
inline
int
__init
xilinxfb_of_register
(
void
)
{
pr_debug
(
"xilinxfb: calling of_register_platform_driver()
\n
"
);
return
of_register_platform_driver
(
&
xilinxfb_of_driver
);
}
static
inline
void
__exit
xilinxfb_of_unregister
(
void
)
{
of_unregister_platform_driver
(
&
xilinxfb_of_driver
);
}
#else
/* CONFIG_OF */
/* CONFIG_OF not enabled; do nothing helpers */
static
inline
int
__init
xilinxfb_of_register
(
void
)
{
return
0
;
}
static
inline
void
__exit
xilinxfb_of_unregister
(
void
)
{
}
#endif
/* CONFIG_OF */
/* ---------------------------------------------------------------------
* Module setup and teardown
*/
static
int
__init
static
int
__init
xilinxfb_init
(
void
)
xilinxfb_init
(
void
)
{
{
/*
int
rc
;
* No kernel boot options used,
rc
=
xilinxfb_of_register
();
* so we just need to register the driver
if
(
rc
)
*/
return
rc
;
return
driver_register
(
&
xilinxfb_driver
);
rc
=
platform_driver_register
(
&
xilinxfb_platform_driver
);
if
(
rc
)
xilinxfb_of_unregister
();
return
rc
;
}
}
static
void
__exit
static
void
__exit
xilinxfb_cleanup
(
void
)
xilinxfb_cleanup
(
void
)
{
{
driver_unregister
(
&
xilinxfb_driver
);
platform_driver_unregister
(
&
xilinxfb_platform_driver
);
xilinxfb_of_unregister
();
}
}
module_init
(
xilinxfb_init
);
module_init
(
xilinxfb_init
);
...
...
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