Commit 88b6f7eb authored by Tony Lindgren's avatar Tony Lindgren

Merge branch 'omap-clock-upstream' of git://git.pwsan.com/linux-2.6 into for-next

parents 8f9ccfee 79716870
...@@ -776,7 +776,7 @@ int __init omap1_clk_init(void) ...@@ -776,7 +776,7 @@ int __init omap1_clk_init(void)
arm_idlect1_mask = ~0; arm_idlect1_mask = ~0;
for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++)
clk_init_one(c->lk.clk); clk_preinit(c->lk.clk);
cpu_mask = 0; cpu_mask = 0;
if (cpu_is_omap16xx()) if (cpu_is_omap16xx())
......
...@@ -547,8 +547,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, ...@@ -547,8 +547,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
const struct clksel_rate *clkr; const struct clksel_rate *clkr;
u32 last_div = 0; u32 last_div = 0;
printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n", pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
clk->name, target_rate); clk->name, target_rate);
*new_div = 1; *new_div = 1;
...@@ -562,7 +562,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, ...@@ -562,7 +562,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
/* Sanity check */ /* Sanity check */
if (clkr->div <= last_div) if (clkr->div <= last_div)
printk(KERN_ERR "clock: clksel_rate table not sorted " pr_err("clock: clksel_rate table not sorted "
"for clock %s", clk->name); "for clock %s", clk->name);
last_div = clkr->div; last_div = clkr->div;
...@@ -574,7 +574,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, ...@@ -574,7 +574,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
} }
if (!clkr->div) { if (!clkr->div) {
printk(KERN_ERR "clock: Could not find divisor for target " pr_err("clock: Could not find divisor for target "
"rate %ld for clock %s parent %s\n", target_rate, "rate %ld for clock %s parent %s\n", target_rate,
clk->name, clk->parent->name); clk->name, clk->parent->name);
return ~0; return ~0;
...@@ -582,8 +582,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, ...@@ -582,8 +582,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
*new_div = clkr->div; *new_div = clkr->div;
printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div, pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
(clk->parent->rate / clkr->div)); (clk->parent->rate / clkr->div));
return (clk->parent->rate / clkr->div); return (clk->parent->rate / clkr->div);
} }
...@@ -1035,7 +1035,7 @@ void omap2_clk_disable_unused(struct clk *clk) ...@@ -1035,7 +1035,7 @@ void omap2_clk_disable_unused(struct clk *clk)
if ((regval32 & (1 << clk->enable_bit)) == v) if ((regval32 & (1 << clk->enable_bit)) == v)
return; return;
printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
if (cpu_is_omap34xx()) { if (cpu_is_omap34xx()) {
omap2_clk_enable(clk); omap2_clk_enable(clk);
omap2_clk_disable(clk); omap2_clk_disable(clk);
......
...@@ -725,7 +725,7 @@ int __init omap2_clk_init(void) ...@@ -725,7 +725,7 @@ int __init omap2_clk_init(void)
clk_init(&omap2_clk_functions); clk_init(&omap2_clk_functions);
for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++) for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
clk_init_one(c->lk.clk); clk_preinit(c->lk.clk);
osc_ck.rate = omap2_osc_clk_recalc(&osc_ck); osc_ck.rate = omap2_osc_clk_recalc(&osc_ck);
propagate_rate(&osc_ck); propagate_rate(&osc_ck);
......
...@@ -281,6 +281,8 @@ static struct omap_clk omap34xx_clks[] = { ...@@ -281,6 +281,8 @@ static struct omap_clk omap34xx_clks[] = {
#define MAX_DPLL_WAIT_TRIES 1000000 #define MAX_DPLL_WAIT_TRIES 1000000
#define MIN_SDRC_DLL_LOCK_FREQ 83000000
/** /**
* omap3_dpll_recalc - recalculate DPLL rate * omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk * @clk: DPLL struct clk
...@@ -703,6 +705,7 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) ...@@ -703,6 +705,7 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
{ {
u32 new_div = 0; u32 new_div = 0;
u32 unlock_dll = 0;
unsigned long validrate, sdrcrate; unsigned long validrate, sdrcrate;
struct omap_sdrc_params *sp; struct omap_sdrc_params *sp;
...@@ -729,17 +732,22 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) ...@@ -729,17 +732,22 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
if (!sp) if (!sp)
return -EINVAL; return -EINVAL;
pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) {
validrate); pr_debug("clock: will unlock SDRC DLL\n");
pr_info("clock: SDRC timing params used: %08x %08x %08x\n", unlock_dll = 1;
sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb); }
pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
validrate);
pr_debug("clock: SDRC timing params used: %08x %08x %08x\n",
sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
/* REVISIT: SRAM code doesn't support other M2 divisors yet */ /* REVISIT: SRAM code doesn't support other M2 divisors yet */
WARN_ON(new_div != 1 && new_div != 2); WARN_ON(new_div != 1 && new_div != 2);
/* REVISIT: Add SDRC_MR changing to this code also */ /* REVISIT: Add SDRC_MR changing to this code also */
omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
sp->actim_ctrlb, new_div); sp->actim_ctrlb, new_div, unlock_dll);
return 0; return 0;
} }
...@@ -956,7 +964,7 @@ int __init omap2_clk_init(void) ...@@ -956,7 +964,7 @@ int __init omap2_clk_init(void)
clk_init(&omap2_clk_functions); clk_init(&omap2_clk_functions);
for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
clk_init_one(c->lk.clk); clk_preinit(c->lk.clk);
for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
if (c->cpu & cpu_clkflg) { if (c->cpu & cpu_clkflg) {
......
...@@ -37,6 +37,10 @@ static struct omap_sdrc_params *sdrc_init_params; ...@@ -37,6 +37,10 @@ static struct omap_sdrc_params *sdrc_init_params;
void __iomem *omap2_sdrc_base; void __iomem *omap2_sdrc_base;
void __iomem *omap2_sms_base; void __iomem *omap2_sms_base;
/* SDRC_POWER register bits */
#define SDRC_POWER_EXTCLKDIS_SHIFT 3
#define SDRC_POWER_PWDENA_SHIFT 2
#define SDRC_POWER_PAGEPOLICY_SHIFT 0
/** /**
* omap2_sdrc_get_params - return SDRC register values for a given clock rate * omap2_sdrc_get_params - return SDRC register values for a given clock rate
...@@ -74,7 +78,14 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals) ...@@ -74,7 +78,14 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals)
omap2_sms_base = omap2_globals->sms; omap2_sms_base = omap2_globals->sms;
} }
/* turn on smart idle modes for SDRAM scheduler and controller */ /**
* omap2_sdrc_init - initialize SMS, SDRC devices on boot
* @sp: pointer to a null-terminated list of struct omap_sdrc_params
*
* Turn on smart idle modes for SDRAM scheduler and controller.
* Program a known-good configuration for the SDRC to deal with buggy
* bootloaders.
*/
void __init omap2_sdrc_init(struct omap_sdrc_params *sp) void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
{ {
u32 l; u32 l;
...@@ -90,4 +101,10 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp) ...@@ -90,4 +101,10 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
sdrc_write_reg(l, SDRC_SYSCONFIG); sdrc_write_reg(l, SDRC_SYSCONFIG);
sdrc_init_params = sp; sdrc_init_params = sp;
/* XXX Enable SRFRONIDLEREQ here also? */
l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
(1 << SDRC_POWER_PWDENA_SHIFT) |
(1 << SDRC_POWER_PAGEPOLICY_SHIFT);
sdrc_write_reg(l, SDRC_POWER);
} }
...@@ -40,69 +40,74 @@ ...@@ -40,69 +40,74 @@
/* /*
* Change frequency of core dpll * Change frequency of core dpll
* r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
* r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for
* SDRC rates < 83MHz
*/ */
ENTRY(omap3_sram_configure_core_dpll) ENTRY(omap3_sram_configure_core_dpll)
stmfd sp!, {r1-r12, lr} @ store regs to stack stmfd sp!, {r1-r12, lr} @ store regs to stack
ldr r4, [sp, #52] @ pull extra args off the stack
dsb @ flush buffered writes to interconnect
cmp r3, #0x2 cmp r3, #0x2
blne configure_sdrc blne configure_sdrc
cmp r3, #0x2 cmp r4, #0x1
bleq unlock_dll
blne lock_dll blne lock_dll
cmp r3, #0x1
blne unlock_dll
bl sdram_in_selfrefresh @ put the SDRAM in self refresh bl sdram_in_selfrefresh @ put the SDRAM in self refresh
bl configure_core_dpll bl configure_core_dpll
bl enable_sdrc bl enable_sdrc
cmp r3, #0x1 cmp r4, #0x1
blne wait_dll_unlock bleq wait_dll_unlock
cmp r3, #0x2
blne wait_dll_lock blne wait_dll_lock
cmp r3, #0x1 cmp r3, #0x1
blne configure_sdrc blne configure_sdrc
isb @ prevent speculative exec past here
mov r0, #0 @ return value mov r0, #0 @ return value
ldmfd sp!, {r1-r12, pc} @ restore regs and return ldmfd sp!, {r1-r12, pc} @ restore regs and return
unlock_dll: unlock_dll:
ldr r4, omap3_sdrc_dlla_ctrl ldr r11, omap3_sdrc_dlla_ctrl
ldr r5, [r4] ldr r12, [r11]
orr r5, r5, #0x4 orr r12, r12, #0x4
str r5, [r4] str r12, [r11] @ (no OCP barrier needed)
bx lr bx lr
lock_dll: lock_dll:
ldr r4, omap3_sdrc_dlla_ctrl ldr r11, omap3_sdrc_dlla_ctrl
ldr r5, [r4] ldr r12, [r11]
bic r5, r5, #0x4 bic r12, r12, #0x4
str r5, [r4] str r12, [r11] @ (no OCP barrier needed)
bx lr bx lr
sdram_in_selfrefresh: sdram_in_selfrefresh:
mov r5, #0x0 @ Move 0 to R5 ldr r11, omap3_sdrc_power @ read the SDRC_POWER register
mcr p15, 0, r5, c7, c10, 5 @ memory barrier ldr r12, [r11] @ read the contents of SDRC_POWER
ldr r4, omap3_sdrc_power @ read the SDRC_POWER register mov r9, r12 @ keep a copy of SDRC_POWER bits
ldr r5, [r4] @ read the contents of SDRC_POWER orr r12, r12, #0x40 @ enable self refresh on idle req
orr r5, r5, #0x40 @ enable self refresh on idle req bic r12, r12, #0x4 @ clear PWDENA
str r5, [r4] @ write back to SDRC_POWER register str r12, [r11] @ write back to SDRC_POWER register
ldr r4, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg ldr r12, [r11] @ posted-write barrier for SDRC
ldr r5, [r4] ldr r11, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg
bic r5, r5, #0x2 @ disable iclk bit for SRDC ldr r12, [r11]
str r5, [r4] bic r12, r12, #0x2 @ disable iclk bit for SDRC
str r12, [r11]
wait_sdrc_idle: wait_sdrc_idle:
ldr r4, omap3_cm_idlest1_core ldr r11, omap3_cm_idlest1_core
ldr r5, [r4] ldr r12, [r11]
and r5, r5, #0x2 @ check for SDRC idle and r12, r12, #0x2 @ check for SDRC idle
cmp r5, #2 cmp r12, #2
bne wait_sdrc_idle bne wait_sdrc_idle
bx lr bx lr
configure_core_dpll: configure_core_dpll:
ldr r4, omap3_cm_clksel1_pll ldr r11, omap3_cm_clksel1_pll
ldr r5, [r4] ldr r12, [r11]
ldr r6, core_m2_mask_val @ modify m2 for core dpll ldr r10, core_m2_mask_val @ modify m2 for core dpll
and r5, r5, r6 and r12, r12, r10
orr r5, r5, r3, lsl #0x1B @ r3 contains the M2 val orr r12, r12, r3, lsl #0x1B @ r3 contains the M2 val
str r5, [r4] str r12, [r11]
mov r5, #0x800 @ wait for the clock to stabilise ldr r12, [r11] @ posted-write barrier for CM
mov r12, #0x800 @ wait for the clock to stabilise
cmp r3, #2 cmp r3, #2
bne wait_clk_stable bne wait_clk_stable
bx lr bx lr
wait_clk_stable: wait_clk_stable:
subs r5, r5, #1 subs r12, r12, #1
bne wait_clk_stable bne wait_clk_stable
nop nop
nop nop
...@@ -116,42 +121,42 @@ wait_clk_stable: ...@@ -116,42 +121,42 @@ wait_clk_stable:
nop nop
bx lr bx lr
enable_sdrc: enable_sdrc:
ldr r4, omap3_cm_iclken1_core ldr r11, omap3_cm_iclken1_core
ldr r5, [r4] ldr r12, [r11]
orr r5, r5, #0x2 @ enable iclk bit for SDRC orr r12, r12, #0x2 @ enable iclk bit for SDRC
str r5, [r4] str r12, [r11]
wait_sdrc_idle1: wait_sdrc_idle1:
ldr r4, omap3_cm_idlest1_core ldr r11, omap3_cm_idlest1_core
ldr r5, [r4] ldr r12, [r11]
and r5, r5, #0x2 and r12, r12, #0x2
cmp r5, #0 cmp r12, #0
bne wait_sdrc_idle1 bne wait_sdrc_idle1
ldr r4, omap3_sdrc_power restore_sdrc_power_val:
ldr r5, [r4] ldr r11, omap3_sdrc_power
bic r5, r5, #0x40 str r9, [r11] @ restore SDRC_POWER, no barrier needed
str r5, [r4]
bx lr bx lr
wait_dll_lock: wait_dll_lock:
ldr r4, omap3_sdrc_dlla_status ldr r11, omap3_sdrc_dlla_status
ldr r5, [r4] ldr r12, [r11]
and r5, r5, #0x4 and r12, r12, #0x4
cmp r5, #0x4 cmp r12, #0x4
bne wait_dll_lock bne wait_dll_lock
bx lr bx lr
wait_dll_unlock: wait_dll_unlock:
ldr r4, omap3_sdrc_dlla_status ldr r11, omap3_sdrc_dlla_status
ldr r5, [r4] ldr r12, [r11]
and r5, r5, #0x4 and r12, r12, #0x4
cmp r5, #0x0 cmp r12, #0x0
bne wait_dll_unlock bne wait_dll_unlock
bx lr bx lr
configure_sdrc: configure_sdrc:
ldr r4, omap3_sdrc_rfr_ctrl ldr r11, omap3_sdrc_rfr_ctrl
str r0, [r4] str r0, [r11]
ldr r4, omap3_sdrc_actim_ctrla ldr r11, omap3_sdrc_actim_ctrla
str r1, [r4] str r1, [r11]
ldr r4, omap3_sdrc_actim_ctrlb ldr r11, omap3_sdrc_actim_ctrlb
str r2, [r4] str r2, [r11]
ldr r2, [r11] @ posted-write barrier for SDRC
bx lr bx lr
omap3_sdrc_power: omap3_sdrc_power:
......
...@@ -240,13 +240,13 @@ void recalculate_root_clocks(void) ...@@ -240,13 +240,13 @@ void recalculate_root_clocks(void)
} }
/** /**
* clk_init_one - initialize any fields in the struct clk before clk init * clk_preinit - initialize any fields in the struct clk before clk init
* @clk: struct clk * to initialize * @clk: struct clk * to initialize
* *
* Initialize any struct clk fields needed before normal clk initialization * Initialize any struct clk fields needed before normal clk initialization
* can run. No return value. * can run. No return value.
*/ */
void clk_init_one(struct clk *clk) void clk_preinit(struct clk *clk)
{ {
INIT_LIST_HEAD(&clk->children); INIT_LIST_HEAD(&clk->children);
} }
......
...@@ -119,7 +119,7 @@ struct clk_functions { ...@@ -119,7 +119,7 @@ struct clk_functions {
extern unsigned int mpurate; extern unsigned int mpurate;
extern int clk_init(struct clk_functions *custom_clocks); extern int clk_init(struct clk_functions *custom_clocks);
extern void clk_init_one(struct clk *clk); extern void clk_preinit(struct clk *clk);
extern int clk_register(struct clk *clk); extern int clk_register(struct clk *clk);
extern void clk_reparent(struct clk *child, struct clk *parent); extern void clk_reparent(struct clk *child, struct clk *parent);
extern void clk_unregister(struct clk *clk); extern void clk_unregister(struct clk *clk);
......
...@@ -23,7 +23,8 @@ extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); ...@@ -23,7 +23,8 @@ extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl,
u32 sdrc_actim_ctrla, u32 sdrc_actim_ctrla,
u32 sdrc_actim_ctrlb, u32 m2); u32 sdrc_actim_ctrlb, u32 m2,
u32 unlock_dll);
/* Do not use these */ /* Do not use these */
extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl); extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
...@@ -60,7 +61,8 @@ extern unsigned long omap243x_sram_reprogram_sdrc_sz; ...@@ -60,7 +61,8 @@ extern unsigned long omap243x_sram_reprogram_sdrc_sz;
extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl, extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl,
u32 sdrc_actim_ctrla, u32 sdrc_actim_ctrla,
u32 sdrc_actim_ctrlb, u32 m2); u32 sdrc_actim_ctrlb, u32 m2,
u32 unlock_dll);
extern unsigned long omap3_sram_configure_core_dpll_sz; extern unsigned long omap3_sram_configure_core_dpll_sz;
#endif #endif
...@@ -201,6 +201,15 @@ void __init omap_map_sram(void) ...@@ -201,6 +201,15 @@ void __init omap_map_sram(void)
base = OMAP3_SRAM_PA; base = OMAP3_SRAM_PA;
base = ROUND_DOWN(base, PAGE_SIZE); base = ROUND_DOWN(base, PAGE_SIZE);
omap_sram_io_desc[0].pfn = __phys_to_pfn(base); omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
/*
* SRAM must be marked as non-cached on OMAP3 since the
* CORE DPLL M2 divider change code (in SRAM) runs with the
* SDRAM controller disabled, and if it is marked cached,
* the ARM may attempt to write cache lines back to SDRAM
* which will cause the system to hang.
*/
omap_sram_io_desc[0].type = MT_MEMORY_NONCACHED;
} }
omap_sram_io_desc[0].length = 1024 * 1024; /* Use section desc */ omap_sram_io_desc[0].length = 1024 * 1024; /* Use section desc */
...@@ -343,14 +352,15 @@ static inline int omap243x_sram_init(void) ...@@ -343,14 +352,15 @@ static inline int omap243x_sram_init(void)
static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl, static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl,
u32 sdrc_actim_ctrla, u32 sdrc_actim_ctrla,
u32 sdrc_actim_ctrlb, u32 sdrc_actim_ctrlb,
u32 m2); u32 m2, u32 unlock_dll);
u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla, u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
u32 sdrc_actim_ctrlb, u32 m2) u32 sdrc_actim_ctrlb, u32 m2, u32 unlock_dll)
{ {
BUG_ON(!_omap3_sram_configure_core_dpll); BUG_ON(!_omap3_sram_configure_core_dpll);
return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl, return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
sdrc_actim_ctrla, sdrc_actim_ctrla,
sdrc_actim_ctrlb, m2); sdrc_actim_ctrlb, m2,
unlock_dll);
} }
/* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */ /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment