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
nexedi
linux
Commits
acd7ef92
Commit
acd7ef92
authored
Apr 25, 2012
by
Alan Cox
Committed by
Dave Airlie
Apr 27, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gma500: Update the Cedarview clock handling
Signed-off-by:
Dave Airlie
<
airlied@redhat.com
>
parent
642c52fc
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
294 additions
and
65 deletions
+294
-65
drivers/gpu/drm/gma500/cdv_intel_display.c
drivers/gpu/drm/gma500/cdv_intel_display.c
+266
-65
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/gma500/psb_intel_drv.h
+3
-0
drivers/gpu/drm/gma500/psb_intel_reg.h
drivers/gpu/drm/gma500/psb_intel_reg.h
+25
-0
No files found.
drivers/gpu/drm/gma500/cdv_intel_display.c
View file @
acd7ef92
...
...
@@ -216,7 +216,7 @@ static void cdv_sb_reset(struct drm_device *dev)
*/
static
int
cdv_dpll_set_clock_cdv
(
struct
drm_device
*
dev
,
struct
drm_crtc
*
crtc
,
struct
cdv_intel_clock_t
*
clock
)
struct
cdv_intel_clock_t
*
clock
,
bool
is_lvds
)
{
struct
psb_intel_crtc
*
psb_crtc
=
to_psb_intel_crtc
(
crtc
);
...
...
@@ -224,6 +224,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
u32
m
,
n_vco
,
p
;
int
ret
=
0
;
int
dpll_reg
=
(
pipe
==
0
)
?
DPLL_A
:
DPLL_B
;
int
ref_sfr
=
(
pipe
==
0
)
?
SB_REF_DPLLA
:
SB_REF_DPLLB
;
u32
ref_value
;
cdv_sb_reset
(
dev
);
...
...
@@ -241,6 +242,35 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
/* We don't know what the other fields of these regs are, so
* leave them in place.
*/
/*
* The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk
* for the pipe A/B. Display spec 1.06 has wrong definition.
* Correct definition is like below:
*
* refclka mean use clock from same PLL
*
* if DPLLA sets 01 and DPLLB sets 01, they use clock from their pll
*
* if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA
*
*/
ret
=
cdv_sb_read
(
dev
,
ref_sfr
,
&
ref_value
);
if
(
ret
)
return
ret
;
ref_value
&=
~
(
REF_CLK_MASK
);
/* use DPLL_A for pipeB on CRT/HDMI */
if
(
pipe
==
1
&&
!
is_lvds
)
{
DRM_DEBUG_KMS
(
"use DPLLA for pipe B
\n
"
);
ref_value
|=
REF_CLK_DPLLA
;
}
else
{
DRM_DEBUG_KMS
(
"use their DPLL for pipe A/B
\n
"
);
ref_value
|=
REF_CLK_DPLL
;
}
ret
=
cdv_sb_write
(
dev
,
ref_sfr
,
ref_value
);
if
(
ret
)
return
ret
;
ret
=
cdv_sb_read
(
dev
,
SB_M
(
pipe
),
&
m
);
if
(
ret
)
return
ret
;
...
...
@@ -308,7 +338,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
return
ret
;
/* always Program the Lane Register for the Pipe A*/
if
(
pipe
==
0
)
{
/* if (pipe == 0) */
{
/* Program the Lane0/1 for HDMI B */
u32
lane_reg
,
lane_value
;
...
...
@@ -553,6 +583,200 @@ static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
return
ret
;
}
#define FIFO_PIPEA (1 << 0)
#define FIFO_PIPEB (1 << 1)
static
bool
cdv_intel_pipe_enabled
(
struct
drm_device
*
dev
,
int
pipe
)
{
struct
drm_crtc
*
crtc
;
struct
drm_psb_private
*
dev_priv
=
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
NULL
;
crtc
=
dev_priv
->
pipe_to_crtc_mapping
[
pipe
];
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
if
(
crtc
->
fb
==
NULL
||
!
psb_intel_crtc
->
active
)
return
false
;
return
true
;
}
static
bool
cdv_intel_single_pipe_active
(
struct
drm_device
*
dev
)
{
uint32_t
pipe_enabled
=
0
;
if
(
cdv_intel_pipe_enabled
(
dev
,
0
))
pipe_enabled
|=
FIFO_PIPEA
;
if
(
cdv_intel_pipe_enabled
(
dev
,
1
))
pipe_enabled
|=
FIFO_PIPEB
;
DRM_DEBUG_KMS
(
"pipe enabled %x
\n
"
,
pipe_enabled
);
if
(
pipe_enabled
==
FIFO_PIPEA
||
pipe_enabled
==
FIFO_PIPEB
)
return
true
;
else
return
false
;
}
static
bool
is_pipeb_lvds
(
struct
drm_device
*
dev
,
struct
drm_crtc
*
crtc
)
{
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
struct
drm_mode_config
*
mode_config
=
&
dev
->
mode_config
;
struct
drm_connector
*
connector
;
if
(
psb_intel_crtc
->
pipe
!=
1
)
return
false
;
list_for_each_entry
(
connector
,
&
mode_config
->
connector_list
,
head
)
{
struct
psb_intel_encoder
*
psb_intel_encoder
=
psb_intel_attached_encoder
(
connector
);
if
(
!
connector
->
encoder
||
connector
->
encoder
->
crtc
!=
crtc
)
continue
;
if
(
psb_intel_encoder
->
type
==
INTEL_OUTPUT_LVDS
)
return
true
;
}
return
false
;
}
static
void
cdv_intel_disable_self_refresh
(
struct
drm_device
*
dev
)
{
if
(
REG_READ
(
FW_BLC_SELF
)
&
FW_BLC_SELF_EN
)
{
/* Disable self-refresh before adjust WM */
REG_WRITE
(
FW_BLC_SELF
,
(
REG_READ
(
FW_BLC_SELF
)
&
~
FW_BLC_SELF_EN
));
REG_READ
(
FW_BLC_SELF
);
cdv_intel_wait_for_vblank
(
dev
);
/* Cedarview workaround to write ovelay plane, which force to leave
* MAX_FIFO state.
*/
REG_WRITE
(
OV_OVADD
,
0
/*dev_priv->ovl_offset*/
);
REG_READ
(
OV_OVADD
);
cdv_intel_wait_for_vblank
(
dev
);
}
}
static
void
cdv_intel_update_watermark
(
struct
drm_device
*
dev
,
struct
drm_crtc
*
crtc
)
{
if
(
cdv_intel_single_pipe_active
(
dev
))
{
u32
fw
;
fw
=
REG_READ
(
DSPFW1
);
fw
&=
~
DSP_FIFO_SR_WM_MASK
;
fw
|=
(
0x7e
<<
DSP_FIFO_SR_WM_SHIFT
);
fw
&=
~
CURSOR_B_FIFO_WM_MASK
;
fw
|=
(
0x4
<<
CURSOR_B_FIFO_WM_SHIFT
);
REG_WRITE
(
DSPFW1
,
fw
);
fw
=
REG_READ
(
DSPFW2
);
fw
&=
~
CURSOR_A_FIFO_WM_MASK
;
fw
|=
(
0x6
<<
CURSOR_A_FIFO_WM_SHIFT
);
fw
&=
~
DSP_PLANE_C_FIFO_WM_MASK
;
fw
|=
(
0x8
<<
DSP_PLANE_C_FIFO_WM_SHIFT
);
REG_WRITE
(
DSPFW2
,
fw
);
REG_WRITE
(
DSPFW3
,
0x36000000
);
/* ignore FW4 */
if
(
is_pipeb_lvds
(
dev
,
crtc
))
{
REG_WRITE
(
DSPFW5
,
0x00040330
);
}
else
{
fw
=
(
3
<<
DSP_PLANE_B_FIFO_WM1_SHIFT
)
|
(
4
<<
DSP_PLANE_A_FIFO_WM1_SHIFT
)
|
(
3
<<
CURSOR_B_FIFO_WM1_SHIFT
)
|
(
4
<<
CURSOR_FIFO_SR_WM1_SHIFT
);
REG_WRITE
(
DSPFW5
,
fw
);
}
REG_WRITE
(
DSPFW6
,
0x10
);
cdv_intel_wait_for_vblank
(
dev
);
/* enable self-refresh for single pipe active */
REG_WRITE
(
FW_BLC_SELF
,
FW_BLC_SELF_EN
);
REG_READ
(
FW_BLC_SELF
);
cdv_intel_wait_for_vblank
(
dev
);
}
else
{
/* HW team suggested values... */
REG_WRITE
(
DSPFW1
,
0x3f880808
);
REG_WRITE
(
DSPFW2
,
0x0b020202
);
REG_WRITE
(
DSPFW3
,
0x24000000
);
REG_WRITE
(
DSPFW4
,
0x08030202
);
REG_WRITE
(
DSPFW5
,
0x01010101
);
REG_WRITE
(
DSPFW6
,
0x1d0
);
cdv_intel_wait_for_vblank
(
dev
);
cdv_intel_disable_self_refresh
(
dev
);
}
}
/** Loads the palette/gamma unit for the CRTC with the prepared values */
static
void
cdv_intel_crtc_load_lut
(
struct
drm_crtc
*
crtc
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
(
struct
drm_psb_private
*
)
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
int
palreg
=
PALETTE_A
;
int
i
;
/* The clocks have to be on to load the palette. */
if
(
!
crtc
->
enabled
)
return
;
switch
(
psb_intel_crtc
->
pipe
)
{
case
0
:
break
;
case
1
:
palreg
=
PALETTE_B
;
break
;
case
2
:
palreg
=
PALETTE_C
;
break
;
default:
dev_err
(
dev
->
dev
,
"Illegal Pipe Number.
\n
"
);
return
;
}
if
(
gma_power_begin
(
dev
,
false
))
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
REG_WRITE
(
palreg
+
4
*
i
,
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]));
}
gma_power_end
(
dev
);
}
else
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
dev_priv
->
regs
.
psb
.
save_palette_a
[
i
]
=
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]);
}
}
}
/**
* Sets the power management mode of the pipe and plane.
*
...
...
@@ -568,15 +792,23 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
int
dspcntr_reg
=
(
pipe
==
0
)
?
DSPACNTR
:
DSPBCNTR
;
int
dspbase_reg
=
(
pipe
==
0
)
?
DSPABASE
:
DSPBBASE
;
int
pipeconf_reg
=
(
pipe
==
0
)
?
PIPEACONF
:
PIPEBCONF
;
int
pipestat_reg
=
(
pipe
==
0
)
?
PIPEASTAT
:
PIPEBSTAT
;
u32
temp
;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
*/
cdv_intel_disable_self_refresh
(
dev
);
switch
(
mode
)
{
case
DRM_MODE_DPMS_ON
:
case
DRM_MODE_DPMS_STANDBY
:
case
DRM_MODE_DPMS_SUSPEND
:
if
(
psb_intel_crtc
->
active
)
return
;
psb_intel_crtc
->
active
=
true
;
/* Enable the DPLL */
temp
=
REG_READ
(
dpll_reg
);
if
((
temp
&
DPLL_VCO_ENABLE
)
==
0
)
{
...
...
@@ -611,13 +843,26 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
if
((
temp
&
PIPEACONF_ENABLE
)
==
0
)
REG_WRITE
(
pipeconf_reg
,
temp
|
PIPEACONF_ENABLE
);
psb_intel_crtc_load_lut
(
crtc
);
temp
=
REG_READ
(
pipestat_reg
);
temp
&=
~
(
0xFFFF
);
temp
|=
PIPE_FIFO_UNDERRUN
;
REG_WRITE
(
pipestat_reg
,
temp
);
REG_READ
(
pipestat_reg
);
cdv_intel_update_watermark
(
dev
,
crtc
);
cdv_intel_crtc_load_lut
(
crtc
);
/* Give the overlay scaler a chance to enable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, true); TODO */
psb_intel_crtc
->
crtc_enable
=
true
;
break
;
case
DRM_MODE_DPMS_OFF
:
if
(
!
psb_intel_crtc
->
active
)
return
;
psb_intel_crtc
->
active
=
false
;
/* Give the overlay scaler a chance to disable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
...
...
@@ -627,6 +872,7 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Jim Bish - changed pipe/plane here as well. */
drm_vblank_off
(
dev
,
pipe
);
/* Wait for vblank for the disable to take effect */
cdv_intel_wait_for_vblank
(
dev
);
...
...
@@ -660,6 +906,8 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Wait for the clocks to turn off. */
udelay
(
150
);
cdv_intel_update_watermark
(
dev
,
crtc
);
psb_intel_crtc
->
crtc_enable
=
false
;
break
;
}
/*Set FIFO Watermarks*/
...
...
@@ -709,6 +957,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
struct
drm_framebuffer
*
old_fb
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
int
pipe
=
psb_intel_crtc
->
pipe
;
int
dpll_reg
=
(
pipe
==
0
)
?
DPLL_A
:
DPLL_B
;
...
...
@@ -757,13 +1006,18 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
if
(
dev_priv
->
dplla_96mhz
)
/* low-end sku, 96/100 mhz */
refclk
=
96000
;
/* Hack selection about ref clk for CRT */
/* Select 27MHz as the reference clk for HDMI */
if
(
is_crt
||
is_hdmi
)
else
/* high-end sku, 27/100 mhz */
refclk
=
27000
;
if
(
is_lvds
&&
dev_priv
->
lvds_use_ssc
)
{
refclk
=
dev_priv
->
lvds_ssc_freq
*
1000
;
DRM_DEBUG_KMS
(
"Use SSC reference clock %d Mhz
\n
"
,
dev_priv
->
lvds_ssc_freq
);
}
drm_mode_debug_printmodeline
(
adjusted_mode
);
ok
=
cdv_intel_find_best_PLL
(
crtc
,
adjusted_mode
->
clock
,
refclk
,
...
...
@@ -779,14 +1033,13 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll
|=
3
;
}
dpll
|=
PLL_REF_INPUT_DREFCLK
;
/* dpll |= PLL_REF_INPUT_DREFCLK; */
dpll
|=
DPLL_SYNCLOCK_ENABLE
;
dpll
|=
DPLL_VGA_MODE_DIS
;
if
(
is_lvds
)
/* if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
else
dpll
|=
DPLLB_MODE_DAC_SERIAL
;
dpll |= DPLLB_MODE_DAC_SERIAL;
*/
/* dpll |= (2 << 11); */
/* setup pipeconf */
...
...
@@ -806,7 +1059,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
REG_WRITE
(
dpll_reg
,
dpll
|
DPLL_VGA_MODE_DIS
|
DPLL_SYNCLOCK_ENABLE
);
REG_READ
(
dpll_reg
);
cdv_dpll_set_clock_cdv
(
dev
,
crtc
,
&
clock
);
cdv_dpll_set_clock_cdv
(
dev
,
crtc
,
&
clock
,
is_lvds
);
udelay
(
150
);
...
...
@@ -903,58 +1156,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
return
0
;
}
/** Loads the palette/gamma unit for the CRTC with the prepared values */
static
void
cdv_intel_crtc_load_lut
(
struct
drm_crtc
*
crtc
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_psb_private
*
dev_priv
=
(
struct
drm_psb_private
*
)
dev
->
dev_private
;
struct
psb_intel_crtc
*
psb_intel_crtc
=
to_psb_intel_crtc
(
crtc
);
int
palreg
=
PALETTE_A
;
int
i
;
/* The clocks have to be on to load the palette. */
if
(
!
crtc
->
enabled
)
return
;
switch
(
psb_intel_crtc
->
pipe
)
{
case
0
:
break
;
case
1
:
palreg
=
PALETTE_B
;
break
;
case
2
:
palreg
=
PALETTE_C
;
break
;
default:
dev_err
(
dev
->
dev
,
"Illegal Pipe Number.
\n
"
);
return
;
}
if
(
gma_power_begin
(
dev
,
false
))
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
REG_WRITE
(
palreg
+
4
*
i
,
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]));
}
gma_power_end
(
dev
);
}
else
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
dev_priv
->
regs
.
psb
.
save_palette_a
[
i
]
=
((
psb_intel_crtc
->
lut_r
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
16
)
|
((
psb_intel_crtc
->
lut_g
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
])
<<
8
)
|
(
psb_intel_crtc
->
lut_b
[
i
]
+
psb_intel_crtc
->
lut_adj
[
i
]);
}
}
}
/**
* Save HW states of giving crtc
...
...
drivers/gpu/drm/gma500/psb_intel_drv.h
View file @
acd7ef92
...
...
@@ -193,6 +193,9 @@ struct psb_intel_crtc {
/*crtc mode setting flags*/
u32
mode_flags
;
bool
active
;
bool
crtc_enable
;
/* Saved Crtc HW states */
struct
psb_intel_crtc_state
*
crtc_state
;
};
...
...
drivers/gpu/drm/gma500/psb_intel_reg.h
View file @
acd7ef92
...
...
@@ -505,6 +505,7 @@
#define PIPE_VSYNC_ENABL (1UL << 25)
#define PIPE_HDMI_AUDIO_UNDERRUN (1UL << 26)
#define PIPE_HDMI_AUDIO_BUFFER_DONE (1UL << 27)
#define PIPE_FIFO_UNDERRUN (1UL << 31)
#define PIPE_HDMI_AUDIO_INT_MASK (PIPE_HDMI_AUDIO_UNDERRUN | \
PIPE_HDMI_AUDIO_BUFFER_DONE)
#define PIPE_EVENT_MASK ((1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)|(1 << 24)|(1 << 23)|(1 << 22)|(1 << 21)|(1 << 20)|(1 << 16))
...
...
@@ -569,12 +570,27 @@ struct dpst_guardband {
#define PIPE_PIXEL_MASK 0x00ffffff
#define PIPE_PIXEL_SHIFT 0
#define FW_BLC_SELF 0x20e0
#define FW_BLC_SELF_EN (1<<15)
#define DSPARB 0x70030
#define DSPFW1 0x70034
#define DSP_FIFO_SR_WM_MASK 0xFF800000
#define DSP_FIFO_SR_WM_SHIFT 23
#define CURSOR_B_FIFO_WM_MASK 0x003F0000
#define CURSOR_B_FIFO_WM_SHIFT 16
#define DSPFW2 0x70038
#define CURSOR_A_FIFO_WM_MASK 0x3F00
#define CURSOR_A_FIFO_WM_SHIFT 8
#define DSP_PLANE_C_FIFO_WM_MASK 0x7F
#define DSP_PLANE_C_FIFO_WM_SHIFT 0
#define DSPFW3 0x7003c
#define DSPFW4 0x70050
#define DSPFW5 0x70054
#define DSP_PLANE_B_FIFO_WM1_SHIFT 24
#define DSP_PLANE_A_FIFO_WM1_SHIFT 16
#define CURSOR_B_FIFO_WM1_SHIFT 8
#define CURSOR_FIFO_SR_WM1_SHIFT 0
#define DSPFW6 0x70058
#define DSPCHICKENBIT 0x70400
#define DSPACNTR 0x70180
...
...
@@ -1290,6 +1306,15 @@ No status bits are changed.
#define SB_N_CB_TUNE_MASK PSB_MASK(25, 24)
#define SB_N_CB_TUNE_SHIFT 24
/* the bit 14:13 is used to select between the different reference clock for Pipe A/B */
#define SB_REF_DPLLA 0x8010
#define SB_REF_DPLLB 0x8030
#define REF_CLK_MASK (0x3 << 13)
#define REF_CLK_CORE (0 << 13)
#define REF_CLK_DPLL (1 << 13)
#define REF_CLK_DPLLA (2 << 13)
/* For the DPLL B, it will use the reference clk from DPLL A when using (2 << 13) */
#define _SB_REF_A 0x8018
#define _SB_REF_B 0x8038
#define SB_REF_SFR(pipe) _PIPE(pipe, _SB_REF_A, _SB_REF_B)
...
...
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